borgmcp 1.1.12 → 1.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assimilate-cmd.d.ts +2 -18
- package/dist/assimilate-cmd.js +40 -41
- package/dist/assimilate-deps.js +3 -3
- package/dist/claude.js +11 -11
- package/dist/clear-rewake-core.d.ts +12 -0
- package/dist/clear-rewake-core.js +2 -0
- package/dist/clear-rewake.d.ts +3 -0
- package/dist/clear-rewake.js +2 -0
- package/dist/cli-help.d.ts +1 -2
- package/dist/cli-help.js +6 -14
- package/dist/codex-app-wake.d.ts +4 -3
- package/dist/codex-remote.d.ts +12 -3
- package/dist/codex-remote.js +1 -1
- package/dist/config-utils.js +3 -3
- package/dist/cubes.d.ts +0 -17
- package/dist/cubes.js +4 -5
- package/dist/index.js +15 -15
- package/dist/launch-gate.d.ts +3 -2
- package/dist/model-presets.d.ts +5 -51
- package/dist/model-presets.js +1 -1
- package/dist/parse-assimilate-args.js +1 -1
- package/dist/regen-format.d.ts +9 -8
- package/dist/regen-format.js +13 -12
- package/dist/remote-client.d.ts +8 -0
- package/dist/remote-client.js +1 -1
- package/dist/role-resolver.d.ts +13 -4
- package/dist/role-resolver.js +1 -1
- package/dist/templates.d.ts +9 -8
- package/dist/templates.js +141 -189
- package/dist/tool-manifest.d.ts +3 -0
- package/dist/tool-manifest.js +1 -1
- package/dist/tool-scope.d.ts +1 -1
- package/dist/tool-scope.js +1 -1
- package/package.json +5 -4
package/dist/remote-client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getIdToken as f,getRefreshToken as m,clearTokens as h}from"./config.js";import{refreshIdToken as S,RefreshTokenInvalidError as g,RefreshTransientError as T}from"./auth.js";import{consolePrefix as j}from"./console-prefix.js";import{debugLog as _}from"./debug.js";import{assertUuidShape as E}from"./evict-drone.js";import{DroneEvictedError as k,DroneFrozenError as C,DRONE_EVICTED_CODE as P,DRONE_FROZEN_CODE as O,errorCodeFromBody as I}from"./drone-lifecycle.js";import{MODEL_DESCRIPTOR_REGEX as D}from"./model-presets.js";import{canonicalizeWorkingRepoIdentity as L}from"./working-repo.js";const A=process.env.BORG_API_URL||"https://api.borgmcp.ai",G=3,M=6e4;let l=null;function b(e){return l||(l=S(e).finally(()=>{l=null}),l)}function J(e){if(e==null)return null;const t=e.trim();return/^\d+$/.test(t)?parseInt(t,10)*1e3:null}function v(e,t,n=M,o=()=>Math.random()*500){const r=e??1e3*(t+1);return Math.min(r,n)+o()}function U(e){const t=(n,o)=>`${n}${/[.:!?]$/.test(n)?"":":"} ${o}`;try{const n=JSON.parse(e);if(typeof n?.error=="string")return typeof n.details=="string"?t(n.error,n.details):n.error;if(n?.error&&typeof n.error=="object"){const o=n.error.message,r=n.error.details??n.details;if(typeof o=="string"&&typeof r=="string")return t(o,r);if(typeof o=="string")return o}if(typeof n?.message=="string"&&typeof n?.details=="string")return t(n.message,n.details);if(typeof n?.message=="string")return n.message}catch{}return e}async function q(e,t,n){const o=n.maxRetries??G;let r=e,i=0;for(;r.status===429&&i<o;){const p=v(J(r.headers.get("Retry-After")),i,n.capMs,n.jitter);n.log?.(`rate limited (429); retrying in ${Math.round(p)}ms (attempt ${i+1}/${o})`),await n.sleep(p),i++,r=await t()}return r}function B(e){return new Promise(t=>setTimeout(t,e))}async function F(){let e=await f();if(!e){const t=await m(),n=t!=null;if(t)try{await b(t),e=await f()}catch(o){if(o instanceof g)await h();else throw o instanceof T?o:new T(`Token refresh failed unexpectedly (your saved login was NOT cleared \u2014 retry; if it persists, restart the borg session): ${o?.message??"unknown"}`)}if(!e)throw new Error(n?"Authentication expired \u2014 your saved login has expired. Run: borg setup":"Authentication required \u2014 you are not signed in. Run: borg setup")}return e}async function H(){const e=await m();if(!e)return null;try{return await b(e),await f()}catch(t){if(t instanceof g&&await h(),t instanceof T)throw t;return null}}async function K(){if(await f())return"valid";const t=await m();if(!t)return"dead";try{return await b(t),await f()?"valid":"transient"}catch(n){return n instanceof g?(await h(),"dead"):"transient"}}async function s(e,t={}){let n=await F();const{droneSession:o,apiUrl:r,headers:i,...p}=t,$=r??A,y=(p.method??"GET").toUpperCase(),w=async c=>{const d={Authorization:`Bearer ${c}`,...i};o&&(d["X-Drone-Session"]=o),_(`\u2192 ${y} ${e}`);const u=await fetch(`${$}${e}`,{...p,headers:d});return _(`\u2190 ${u.status} ${y} ${e}`),u};let a=await w(n);if(a.status===401){const c=await H();c&&(n=c,a=await w(n))}if(a.status===401)throw new Error("Authentication required. Run: borg setup");if(a.status===429&&(a=await q(a,()=>w(n),{sleep:B,log:c=>console.error(`${j()}${c}`)})),!a.ok){const c=await a.text();_(`\u2717 ${a.status} ${y} ${e}: ${c}`);const d=U(c),u=I(c);if(a.status===410&&u===P)throw new k(d);if(a.status===423&&u===O)throw new C(d);if(a.status===429){const x=a.headers.get("Retry-After"),R=x?` (retry after ${x}s)`:"";throw new Error(`HTTP 429: rate limited${R}: ${d}`)}throw new Error(`HTTP ${a.status}: ${d}`)}return a}async function ee(e,t,n,o){const r={hostname:n??null};if((o==="claude"||o==="codex"||o==="opencode")&&(r.agent_kind=o),typeof e=="string")r.cube_name=e;else if(e.cube_id&&(r.cube_id=e.cube_id),e.cube_name&&(r.cube_name=e.cube_name),e.role_id&&(r.role_id=e.role_id),e.role_name&&(r.role_name=e.role_name),e.prior_drone_id&&(r.prior_drone_id=e.prior_drone_id),e.model!=null){if(!D.test(e.model))throw new Error(`Invalid model descriptor: "${e.model}" (expected "<claude|ollama>:<model>").`);r.model=e.model}return await(await s("/api/assimilate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),apiUrl:t})).json()}async function ne(e,t){return await(await s("/api/drone/cube",{method:"GET",droneSession:e,apiUrl:t})).json()}async function te(e,t){return await(await s("/api/drone/role",{method:"GET",droneSession:e,apiUrl:t})).json()}async function oe(e,t,n){const o=new URLSearchParams({role:n});return await(await s(`/api/drone/role?${o.toString()}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function re(e,t){return await(await s("/api/drone/whoami",{method:"GET",droneSession:e,apiUrl:t})).json()}async function se(e,t,n){const o=n?`?since=${encodeURIComponent(n)}`:"";return await(await s(`/api/drone/roster${o}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function ie(e,t,n={}){const o=new URLSearchParams;n.since&&o.set("since",n.since),n.limit!==void 0&&o.set("limit",String(n.limit)),n.unreadOnly&&o.set("unread_only","true");const r=o.toString();return await(await s(`/api/drone/log${r?`?${r}`:""}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function ae(e,t,n,o="ack"){await s(`/api/drone/log/${n}/ack`,{method:"POST",body:JSON.stringify({kind:o}),droneSession:e,apiUrl:t})}async function ce(e,t,n){return await(await s("/api/drone/decide",{method:"POST",body:JSON.stringify(n),droneSession:e,apiUrl:t})).json()}async function pe(e,t,n){const o=n?`?topic=${encodeURIComponent(n)}`:"";return await(await s(`/api/drone/decisions${o}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function de(e,t,n={}){const o=new URLSearchParams;if(n.since&&o.set("since",n.since),n.reportedModel&&o.set("reported_model",n.reportedModel),n.workingRepo){o.set("working_repo_reported","1");const p=n.workingRepo.origin?L(n.workingRepo.origin):null;p&&o.set("working_repo_origin",p)}const r=o.toString();return await(await s(`/api/drone/regen${r?`?${r}`:""}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function ue(e,t,n,o){const r=new URLSearchParams({role:n,section:o});return await(await s(`/api/drone/role-rationale?${r.toString()}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function fe(e,t,n,o={}){const r={message:n,...o.visibility?{visibility:o.visibility}:{},...o.recipientDroneIds?{recipientDroneIds:o.recipientDroneIds}:{},...o.class?{class:o.class}:{},...o.to?{to:o.to}:{}};return await(await s("/api/drone/log",{method:"POST",headers:{"Content-Type":"application/json"},droneSession:e,apiUrl:t,body:JSON.stringify(r)})).json()}async function le(e,t,n){const o={kind:n.kind??"friction",message:n.message,...n.metadata?{metadata:n.metadata}:{}};return await(await s("/api/drone/report",{method:"POST",headers:{"Content-Type":"application/json"},droneSession:e,apiUrl:t,body:JSON.stringify(o)})).json()}async function ye(){const e=await s("/api/reports",{method:"GET"});if(e.status===403)return{forbidden:!0};if(!e.ok)throw new Error(`Failed to fetch reports: ${e.status}`);return{forbidden:!1,reports:(await e.json()).reports}}async function we(){return await(await s("/api/cubes",{method:"GET"})).json()}async function me(){return await(await s("/api/templates",{method:"GET"})).json()}async function he(e,t,n){const o={cube_directive:t};e&&(o.name=e),n?.template&&(o.template=n.template),n&&Object.prototype.hasOwnProperty.call(n,"message_taxonomy")&&(o.message_taxonomy=n.message_taxonomy??null);const i=await(await s("/api/cubes",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)})).json();return i.cube?{...i.cube,roles:i.roles??[],drones:i.drones??[]}:i}async function ge(e,t){return await(await s(`/api/cubes/${e}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async function Te(e,t){return await(await s(`/api/cubes/${e}/taxonomy-patch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async function _e(e){await s(`/api/cubes/${e}`,{method:"DELETE"})}async function be(e,t){return await(await s(`/api/cubes/${e}/roles`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async function xe(e,t){return await(await s(`/api/roles/${e}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async function Ee(e,t){return await(await s(`/api/roles/${e}/section-patch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async function $e(e){await s(`/api/roles/${e}`,{method:"DELETE"})}async function Re(e,t){return E(e,"drone_id"),await(await s(`/api/drones/${e}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({role_id:t})})).json()}async function Se(e){E(e,"drone_id"),await s(`/api/drones/${e}`,{method:"DELETE"})}async function je(e){const n=await(await s(`/api/cubes/${e}`,{method:"GET"})).json();return n.cube?{...n.cube,roles:n.roles??[],drones:n.drones??[]}:n}async function ke(e,t){return await(await s(`/api/cubes/${e}/apply-template`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template_name:t})})).json()}async function Ce(){return await(await s("/api/subscription/status",{method:"GET"})).json()}async function Pe(e,t="software-dev",n=!1,o){return await(await s(`/api/cubes/${e}/sync-roles`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template_name:t,apply:n,...o?{decisions:o}:{}})})).json()}async function Oe(){const t=await(await s("/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"}})).json();if(!t.checkout_url)throw new Error("No checkout URL in response");return t.checkout_url}async function Ie(){const t=await(await s("/api/subscription/portal",{method:"POST",headers:{"Content-Type":"application/json"}})).json();if(!t.portal_url)throw new Error(t.message||"No portal URL in response");return t.portal_url}export{A as API_URL,ae as ackLogEntry,fe as appendLog,ke as applyTemplate,ee as assimilate,Ce as checkSubscriptionStatus,Ie as createBillingPortalSession,he as createCube,be as createRole,Oe as createSubscription,_e as deleteCube,$e as deleteRole,Se as evictDrone,U as extractHttpErrorMessage,ye as fetchReports,je as getCube,ne as getCubeInfo,te as getRoleInfo,oe as getRoleInfoByName,se as getRoster,F as getValidToken,we as listCubes,pe as listDecisions,me as listTemplates,J as parseRetryAfterMs,Ee as patchRoleSection,Te as patchTaxonomyClass,K as probeSession,v as rateLimitWaitMs,ie as readLog,Re as reassignDrone,ce as recordDecision,de as regen,q as retryOn429,ue as roleRationale,le as submitReport,Pe as syncRoles,ge as updateCube,xe as updateRole,re as whoami};
|
|
1
|
+
import{getIdToken as f,getRefreshToken as m,clearTokens as h}from"./config.js";import{refreshIdToken as S,RefreshTokenInvalidError as g,RefreshTransientError as T}from"./auth.js";import{consolePrefix as j}from"./console-prefix.js";import{debugLog as E}from"./debug.js";import{assertUuidShape as x}from"./evict-drone.js";import{DroneEvictedError as k,DroneFrozenError as C,DRONE_EVICTED_CODE as P,DRONE_FROZEN_CODE as O,errorCodeFromBody as I}from"./drone-lifecycle.js";import{canonicalizeWorkingRepoIdentity as D}from"./working-repo.js";const L=/^(claude|ollama):[A-Za-z0-9._:\/-]+$/,A=process.env.BORG_API_URL||"https://api.borgmcp.ai",G=3,J=6e4;let l=null;function _(e){return l||(l=S(e).finally(()=>{l=null}),l)}function M(e){if(e==null)return null;const t=e.trim();return/^\d+$/.test(t)?parseInt(t,10)*1e3:null}function v(e,t,n=J,o=()=>Math.random()*500){const r=e??1e3*(t+1);return Math.min(r,n)+o()}function U(e){const t=(n,o)=>`${n}${/[.:!?]$/.test(n)?"":":"} ${o}`;try{const n=JSON.parse(e);if(typeof n?.error=="string")return typeof n.details=="string"?t(n.error,n.details):n.error;if(n?.error&&typeof n.error=="object"){const o=n.error.message,r=n.error.details??n.details;if(typeof o=="string"&&typeof r=="string")return t(o,r);if(typeof o=="string")return o}if(typeof n?.message=="string"&&typeof n?.details=="string")return t(n.message,n.details);if(typeof n?.message=="string")return n.message}catch{}return e}async function N(e,t,n){const o=n.maxRetries??G;let r=e,i=0;for(;r.status===429&&i<o;){const p=v(M(r.headers.get("Retry-After")),i,n.capMs,n.jitter);n.log?.(`rate limited (429); retrying in ${Math.round(p)}ms (attempt ${i+1}/${o})`),await n.sleep(p),i++,r=await t()}return r}function q(e){return new Promise(t=>setTimeout(t,e))}async function B(){let e=await f();if(!e){const t=await m(),n=t!=null;if(t)try{await _(t),e=await f()}catch(o){if(o instanceof g)await h();else throw o instanceof T?o:new T(`Token refresh failed unexpectedly (your saved login was NOT cleared \u2014 retry; if it persists, restart the borg session): ${o?.message??"unknown"}`)}if(!e)throw new Error(n?"Authentication expired \u2014 your saved login has expired. Run: borg setup":"Authentication required \u2014 you are not signed in. Run: borg setup")}return e}async function F(){const e=await m();if(!e)return null;try{return await _(e),await f()}catch(t){if(t instanceof g&&await h(),t instanceof T)throw t;return null}}async function Q(){if(await f())return"valid";const t=await m();if(!t)return"dead";try{return await _(t),await f()?"valid":"transient"}catch(n){return n instanceof g?(await h(),"dead"):"transient"}}async function s(e,t={}){let n=await B();const{droneSession:o,apiUrl:r,headers:i,...p}=t,$=r??A,y=(p.method??"GET").toUpperCase(),w=async c=>{const d={Authorization:`Bearer ${c}`,...i};o&&(d["X-Drone-Session"]=o),E(`\u2192 ${y} ${e}`);const u=await fetch(`${$}${e}`,{...p,headers:d});return E(`\u2190 ${u.status} ${y} ${e}`),u};let a=await w(n);if(a.status===401){const c=await F();c&&(n=c,a=await w(n))}if(a.status===401)throw new Error("Authentication required. Run: borg setup");if(a.status===429&&(a=await N(a,()=>w(n),{sleep:q,log:c=>console.error(`${j()}${c}`)})),!a.ok){const c=await a.text();E(`\u2717 ${a.status} ${y} ${e}: ${c}`);const d=U(c),u=I(c);if(a.status===410&&u===P)throw new k(d);if(a.status===423&&u===O)throw new C(d);if(a.status===429){const b=a.headers.get("Retry-After"),R=b?` (retry after ${b}s)`:"";throw new Error(`HTTP 429: rate limited${R}: ${d}`)}throw new Error(`HTTP ${a.status}: ${d}`)}return a}async function K(e,t,n,o){const r={hostname:n??null};if((o==="claude"||o==="codex"||o==="opencode")&&(r.agent_kind=o),typeof e=="string")r.cube_name=e;else if(e.cube_id&&(r.cube_id=e.cube_id),e.cube_name&&(r.cube_name=e.cube_name),e.role_id&&(r.role_id=e.role_id),e.role_name&&(r.role_name=e.role_name),e.prior_drone_id&&(r.prior_drone_id=e.prior_drone_id),e.model!=null){if(!L.test(e.model))throw new Error(`Invalid model descriptor: "${e.model}" (expected "<claude|ollama>:<model>").`);r.model=e.model}return await(await s("/api/assimilate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),apiUrl:t})).json()}async function ee(e,t){return await(await s("/api/drone/cube",{method:"GET",droneSession:e,apiUrl:t})).json()}async function ne(e,t){return await(await s("/api/drone/role",{method:"GET",droneSession:e,apiUrl:t})).json()}async function te(e,t,n){const o=new URLSearchParams({role:n});return await(await s(`/api/drone/role?${o.toString()}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function oe(e,t){return await(await s("/api/drone/whoami",{method:"GET",droneSession:e,apiUrl:t})).json()}async function re(e,t,n){const o=n?`?since=${encodeURIComponent(n)}`:"";return await(await s(`/api/drone/roster${o}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function se(e,t,n={}){const o=new URLSearchParams;n.since&&o.set("since",n.since),n.limit!==void 0&&o.set("limit",String(n.limit)),n.unreadOnly&&o.set("unread_only","true");const r=o.toString();return await(await s(`/api/drone/log${r?`?${r}`:""}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function ie(e,t,n,o="ack"){await s(`/api/drone/log/${n}/ack`,{method:"POST",body:JSON.stringify({kind:o}),droneSession:e,apiUrl:t})}async function ae(e,t,n){return await(await s("/api/drone/decide",{method:"POST",body:JSON.stringify(n),droneSession:e,apiUrl:t})).json()}async function ce(e,t,n){const o=n?`?topic=${encodeURIComponent(n)}`:"";return await(await s(`/api/drone/decisions${o}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function pe(e,t,n){return await(await s("/api/drone/decisions",{method:"DELETE",body:JSON.stringify(n),droneSession:e,apiUrl:t})).json()}async function de(e,t,n={}){const o=new URLSearchParams;if(n.since&&o.set("since",n.since),n.reportedModel&&o.set("reported_model",n.reportedModel),n.workingRepo){o.set("working_repo_reported","1");const p=n.workingRepo.origin?D(n.workingRepo.origin):null;p&&o.set("working_repo_origin",p)}const r=o.toString();return await(await s(`/api/drone/regen${r?`?${r}`:""}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function ue(e,t,n,o){const r=new URLSearchParams({role:n,section:o});return await(await s(`/api/drone/role-rationale?${r.toString()}`,{method:"GET",droneSession:e,apiUrl:t})).json()}async function fe(e,t,n,o={}){const r={message:n,...o.visibility?{visibility:o.visibility}:{},...o.recipientDroneIds?{recipientDroneIds:o.recipientDroneIds}:{},...o.class?{class:o.class}:{},...o.to?{to:o.to}:{}};return await(await s("/api/drone/log",{method:"POST",headers:{"Content-Type":"application/json"},droneSession:e,apiUrl:t,body:JSON.stringify(r)})).json()}async function le(e,t,n){const o={kind:n.kind??"friction",message:n.message,...n.metadata?{metadata:n.metadata}:{}};return await(await s("/api/drone/report",{method:"POST",headers:{"Content-Type":"application/json"},droneSession:e,apiUrl:t,body:JSON.stringify(o)})).json()}async function ye(){const e=await s("/api/reports",{method:"GET"});if(e.status===403)return{forbidden:!0};if(!e.ok)throw new Error(`Failed to fetch reports: ${e.status}`);return{forbidden:!1,reports:(await e.json()).reports}}async function we(){return await(await s("/api/cubes",{method:"GET"})).json()}async function me(){return await(await s("/api/templates",{method:"GET"})).json()}async function he(e,t,n){const o={cube_directive:t};e&&(o.name=e),n?.template&&(o.template=n.template),n&&Object.prototype.hasOwnProperty.call(n,"message_taxonomy")&&(o.message_taxonomy=n.message_taxonomy??null);const i=await(await s("/api/cubes",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)})).json();return i.cube?{...i.cube,roles:i.roles??[],drones:i.drones??[]}:i}async function ge(e,t){return await(await s(`/api/cubes/${e}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async function Te(e,t){return await(await s(`/api/cubes/${e}/taxonomy-patch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async function Ee(e){await s(`/api/cubes/${e}`,{method:"DELETE"})}async function _e(e,t){return await(await s(`/api/cubes/${e}/roles`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async function be(e,t){return await(await s(`/api/roles/${e}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async function xe(e,t){return await(await s(`/api/roles/${e}/section-patch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async function $e(e){await s(`/api/roles/${e}`,{method:"DELETE"})}async function Re(e,t){return x(e,"drone_id"),await(await s(`/api/drones/${e}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({role_id:t})})).json()}async function Se(e){x(e,"drone_id"),await s(`/api/drones/${e}`,{method:"DELETE"})}async function je(e){const n=await(await s(`/api/cubes/${e}`,{method:"GET"})).json();return n.cube?{...n.cube,roles:n.roles??[],drones:n.drones??[]}:n}async function ke(e,t){return await(await s(`/api/cubes/${e}/apply-template`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template_name:t})})).json()}async function Ce(){return await(await s("/api/subscription/status",{method:"GET"})).json()}async function Pe(e,t="software-dev",n=!1,o){return await(await s(`/api/cubes/${e}/sync-roles`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template_name:t,apply:n,...o?{decisions:o}:{}})})).json()}async function Oe(){const t=await(await s("/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"}})).json();if(!t.checkout_url)throw new Error("No checkout URL in response");return t.checkout_url}async function Ie(){const t=await(await s("/api/subscription/portal",{method:"POST",headers:{"Content-Type":"application/json"}})).json();if(!t.portal_url)throw new Error(t.message||"No portal URL in response");return t.portal_url}export{A as API_URL,ie as ackLogEntry,fe as appendLog,ke as applyTemplate,K as assimilate,Ce as checkSubscriptionStatus,Ie as createBillingPortalSession,he as createCube,_e as createRole,Oe as createSubscription,Ee as deleteCube,$e as deleteRole,Se as evictDrone,U as extractHttpErrorMessage,ye as fetchReports,je as getCube,ee as getCubeInfo,ne as getRoleInfo,te as getRoleInfoByName,re as getRoster,B as getValidToken,we as listCubes,ce as listDecisions,me as listTemplates,M as parseRetryAfterMs,xe as patchRoleSection,Te as patchTaxonomyClass,Q as probeSession,v as rateLimitWaitMs,se as readLog,Re as reassignDrone,ae as recordDecision,de as regen,pe as removeDecision,N as retryOn429,ue as roleRationale,le as submitReport,Pe as syncRoles,ge as updateCube,be as updateRole,oe as whoami};
|
package/dist/role-resolver.d.ts
CHANGED
|
@@ -7,6 +7,16 @@ export interface Role {
|
|
|
7
7
|
role_class?: 'queen' | 'worker';
|
|
8
8
|
default_model?: string | null;
|
|
9
9
|
}
|
|
10
|
+
export interface RoleOccupant {
|
|
11
|
+
role_id: string;
|
|
12
|
+
/** Server-derived advisory; absent remains occupied for rollout safety. */
|
|
13
|
+
presumed_abandoned?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Build the advisory occupancy set used only by role-less assimilation.
|
|
17
|
+
* Explicit role selection and server authorization do not consult it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function occupiedRoleIdsForAutoRole(drones: readonly RoleOccupant[]): Set<string>;
|
|
10
20
|
/**
|
|
11
21
|
* Normalize a role-name argument or stored name into a slug used for
|
|
12
22
|
* both worktree-path construction and role lookup. Single source of
|
|
@@ -35,10 +45,9 @@ export declare function matchRoleByName(roles: Role[], query: string): Role | un
|
|
|
35
45
|
* - If every eligible worker role is occupied → the is_default role.
|
|
36
46
|
* - Neither available → undefined (caller errors out).
|
|
37
47
|
*
|
|
38
|
-
* `occupiedRoleIds` is the set of role_ids that
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* else default".
|
|
48
|
+
* `occupiedRoleIds` is the set of role_ids that still hold a live-enough active
|
|
49
|
+
* seat for automatic selection. Omitted → treated as empty (all roles
|
|
50
|
+
* unoccupied), which degrades to "first eligible worker role, else default".
|
|
42
51
|
*/
|
|
43
52
|
export declare function pickDefaultRole(roles: Role[], opts: {
|
|
44
53
|
isFirstDrone: boolean;
|
package/dist/role-resolver.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function c(n){return new Set(n.filter(t=>t.presumed_abandoned!==!0).map(t=>t.role_id))}function r(n){return n.toLowerCase().replace(/[_\s]+/g,"-").replace(/[^a-z0-9-]/g,"")}function s(n,t){const i=r(t);return n.find(o=>r(o.name)===i)}function d(n,t){if(t.isFirstDrone){const e=n.find(u=>u.is_human_seat);if(e)return e}const i=t.occupiedRoleIds??new Set,o=n.filter(e=>e.is_mandatory===!0&&e.role_class!=="queen"),a=n.filter(e=>e.role_class!=="queen"&&!e.is_human_seat);return o.find(e=>!i.has(e.id))??a.find(e=>!i.has(e.id))??n.find(e=>e.is_default)}export{s as matchRoleByName,c as occupiedRoleIdsForAutoRole,d as pickDefaultRole,r as roleSlug};
|
package/dist/templates.d.ts
CHANGED
|
@@ -43,14 +43,15 @@ export interface MessageTaxonomyClass {
|
|
|
43
43
|
lifecycle?: 'dispatch' | 'completion';
|
|
44
44
|
}
|
|
45
45
|
export type MessageTaxonomy = MessageTaxonomyClass[];
|
|
46
|
-
export declare const ESCALATION_DISCIPLINE = "\n\n**Escalation discipline:**\n- The cube hierarchy is Drones \u2194 your cube's coordinating role \u2194 Queen. Address the coordinating role when blocked; **never** address Queen directly via cube messages.\n- When blocked \u2014 missing context, ambiguous scope, harness rejection, environment issue, anything \u2014 post to cube log with a structured frame: \"<coordinating role>: blocker X, options A/B/C, my pick is B.\" The coordinating role either resolves in-lane OR escalates to Queen if the decision is genuinely Queen-class.\n- **Do NOT
|
|
47
|
-
export declare const ANTI_PASSIVE_STANDING_DISCIPLINE = "\n\n**Anti-passive-Standing discipline:**\n\n`Standing.` is the correct reply to an in-progress transition. It is the WRONG reply when the next expected signal is overdue. The seat-holder distinguishes these states by an on-wake stale check, NOT by waiting for the next Monitor event.\n\n**On every Monitor wake AND every ScheduleWakeup heartbeat \u2014 run the stale check using the cheapest sufficient Borg read:**\n0. Routine wake triage starts with `borg_read-log unread_only=true` \u2014 NOT a manual `since` cursor or bare `limit` (those skip during bursts; `unread_only` reads from your server-side read cursor, oldest-unread first, advancing on each call, so you never miss an entry). DRAIN: if it returns a full set (count == limit) or `borg_roster` shows `behind_by` > 0, call `read-log unread_only=true` again until the return is < limit. Reserve `limit` for explicit bounded reads (e.g. a vote tally). `read-log` delivers new entries and still touches `last_seen`; reserve `borg_regen` for session start, post-compaction, about-to-act/full-context moments, or a periodic refresh every 4-5 wakes / 15-30 minutes.\n1. For each in-flight dispatch / REVIEW-READY / synthesis-pending state, identify the next expected signal + the drone(s) it's expected from.\n2. Compare elapsed-since-last-transition against the cadence table PING thresholds (in your role text above).\n3. If ANY row is past its PING threshold, you do NOT post `Standing.` \u2014 you take action per the escalation ladder below.\n\n**Escalation ladder (concrete; do not improvise \u2014 pick the lowest step that applies):**\n\n- **Step 1 \u2014 PING the specific drone** (when elapsed > PING threshold for that phase):\n Post `PING: <drone-label> \u2014 you ACK'd <thing> at HH:MM:SSZ; current status?` to the cube log. Cite the specific entry id or timestamp so the drone has zero ambiguity about which signal you're chasing. Wait one cadence-bucket (typically 5-10 min) for response.\n\n- **Step 2 \u2014 Probe the drone's liveness** (when PING gets no response within one cadence-bucket):\n Run `borg_roster since=<dispatch-entry-id>` to check the drone's `awake`/`stale-since-X` marker AND `last_log_post` freshness. If the drone is marked stale, proceed to Step 3. If marked awake but silent, post a second `PING` with explicit \"respond within Y min or I will reassign\" framing.\n\n- **Step 3 \u2014 Reassign the role** (when the drone is confirmed unresponsive: silent past 2x PING threshold AND `borg_roster` shows stale `last_log_post`):\n Pick a confirmed-alive drone (recent `awake` marker) compatible with the role. Run `borg_reassign-drone` to move the role assignment. Post a reassignment notice in the cube log naming the previous drone + the new drone + the work item handed over. Brief the new drone on the in-flight state. If the previous drone reconnects later, they post a returning-from-stall message; you decide whether to re-reassign or leave the current assignment in place.\n\n- **Step 4 \u2014 Suspect systemic failure** (when 3+ drones go simultaneously silent past their PING thresholds, or when reassignments themselves don't produce engagement):\n Stop reassigning. Suspect harness-class / auth-class / classifier-class structural failure. Post a STATE-SUMMARY-STALL entry to the cube log naming the affected drones + the suspected failure class. Surface to Queen (or to the human Queen on next return if autonomous) \u2014 this class of failure is above the Coordinator's resolution authority because the failure mode itself prevents normal dispatch from working.\n\n**Coordinator/Queen seats DO NOT STAND:** `Standing` is BANNED for the Coordinator-class seat. The earlier \"Standing-with-explicit-reason\" rule was a half-measure that still produced visibly idle turns; the directive now is unconditional \u2014 there is always productive Coordinator work, even when no gate is overdue and no dispatch is in flight. If you can't post `Standing`, you have to find something to do.\n\n**What \"productive Coordinator work\" looks like when no urgent dispatch is in flight:**\n- **Pre-stage the next merge artifact.** If a PR is mid-review at 4/5, open the gh PR + draft the merge-commit body NOW so the final APPROVED triggers one command. Don't wait for the vote to start the prep work.\n- **File the FRICTION you observed but didn't yet write up.** Per the cube directive, every friction observation is a tracked issue. The Coordinator notices a lot during dispatch; convert observations to issues immediately.\n- **Audit open issues for sprint-candidate triage.** Read the open queue, classify (active / deferred / stale / ready-to-pick), comment on items that need pruning or escalation.\n- **Smoke-test what just shipped.** A merge+deploy from earlier in the session is now in production \u2014 verify the user-facing surface actually behaves as the merge claimed. Catch broken-ship issues before users do.\n- **Update durable docs.** CLAUDE.md, role descriptions, runbook docs \u2014 small drifts noticed during the session that warrant codification.\n- **Probe drone liveness pre-emptively** via `borg_roster` \u2014 surface stale drones before they become a blocker on the next dispatch.\n- **Pre-validate next-sprint dispatches.** If the next sprint is implied by current state, draft the dispatch text + scope notes so it lands cleanly when current sprint completes.\n- **Run the on-wake stale check** (which IS standing-equivalent action even when nothing's overdue \u2014 it produces a snapshot of cube state, not a Standing reply).\n\n**The forcing function:** if you're about to type `Standing for X`, instead post the work you're doing while waiting. If you're not doing work while waiting, the new directive says you ARE failing \u2014 find work.\n\n**Verify-before-claiming (paired discipline):** the no-Standing directive trades correctness for velocity at the synthesis step. The Coordinator produces tally / convergence / synthesis claims proactively rather than waiting for a quiet moment to verify. WITHOUT a verify gate, this produces hallucinated tallies \u2014 listing votes that have NOT been verified via a fresh log read. Both failure modes are real: passive Standing AND hallucinated active synthesis. The paired discipline:\n\n- Before posting any tally / convergence / synthesis claim that names specific drone votes or counts, run `borg_read-log limit \u226510` for brainstorm-class threads OR `limit \u22655` for gate-convergence threads.\n- For gate-convergence threads, the canonical lens-vote format is `GATE-PASS: <lens-name>` followed by the disposition; pattern-match for this in the scan. Legacy formats accepted: `REVIEW-APPROVED` (CR), `SECURITY-APPROVED` (SR), `UX-APPROVED` (UX), `QA-PASS` (QA), `PM-APPROVED` (PM). Encourage `GATE-PASS:` for new posts; tolerate legacy for in-flight votes.\n- If the scan misses a recent post (Monitor race / regen cursor stale), explicitly re-read on the next iteration before re-claiming the tally. ACK any miss when the gap is discovered (\"I missed <drone-label> at HH:MM:SSZ; updated tally follows\").\n\n**Canonical lens-vote format** (adopt `GATE-PASS:` going forward):\n```\nGATE-PASS: <lens> <branch> @ <commit-sha>\n<one-line disposition>\n```\nExamples: `GATE-PASS: CR feat/foo @ abc1234`, `GATE-PASS: SR feat/foo @ abc1234`. Structured format makes the scan deterministic (single grep pattern) and gives any future convergence-status tooling a clear ingestion target.\n\n**Coordinator owns deadlock resolution (HIGH-PRIORITY DIRECTIVE):**\n\nWhen the cube is at risk of deadlock \u2014 any pattern where progress requires action but no drone has explicit ownership of the required action \u2014 the Coordinator (or Queen seat in autonomous mode) is responsible for resolving the situation by **explicitly assigning the action to a named drone**. Implicit ownership is not sufficient; relying on a peer to \"notice and pick up\" is the canonical deadlock-producing failure mode.\n\n**Common deadlock classes the Coordinator resolves**:\n\n- **Author-gate-conflict**: when a gate-bearing drone (CR / SR / QA / UX / PM / etc.) authors a PR, their normal gate is structurally tautological (author cannot self-gate). Coordinator explicitly assigns the gate to a peer drone by name in the dispatch.\n- **Cross-blocked silence**: when drone-A is waiting on drone-B and drone-B is waiting on drone-A (each tracking the other as upstream), neither is wrong but neither will move. Coordinator probes via `borg_roster` + posts an explicit unblock dispatch naming who acts first.\n- **Conditional dispatch with no enforcer**: \"If drone-X is silent by time T, drone-Y takes over\" produces no action unless the Coordinator arms their own ScheduleWakeup at deadline T to enforce the conditional.\n- **Unowned action surface**: a PR needs a deploy, a publish, a follow-up issue, etc., but the dispatch didn't name an owner. Coordinator assigns or executes themselves.\n- **Multi-drone NIT disagreement**: two drones flag conflicting NITs on the same PR with no resolution path. Coordinator synthesizes (no-collapse) and explicitly picks.\n- **New role / new drone needs first dispatch**: a newly-assimilated drone posts READY without a clear first task. Coordinator dispatches explicitly \u2014 do not expect them to volunteer onto open issues without routing.\n\n**Forcing function**: if you (Coordinator) see two posts that imply \"someone should pick this up\" without naming who, that's a deadlock-risk signal. Assign explicitly within one cadence-bucket (5-15 min per the cadence table). Escalate to Queen ONLY for Queen-class assignment decisions.\n\n**Companion bottom-up rule \u2014 idle drones may volunteer cross-role**: idle drones (capacity clean, no in-flight work) may volunteer to pick up unowned cross-role tasks even when the work doesn't match their primary role description, provided: (a) the work is visible in the cube log as unowned (REVIEW-READY without an explicit assignee for the gate-class they're volunteering for; OR a Coordinator post tagged with \"needs cross-coverage\"), (b) the volunteer drone posts `VOLUNTEER: <task> \u2014 <lens-axis I'm covering>` BEFORE doing the work so the Coordinator + cube see the claim, (c) the volunteer drone explicitly names which axis-lens they're applying (e.g., a CR-axis drone volunteering for QA-by-non-author posts `VOLUNTEER: <branch> \u2014 QA-axis cross-coverage from CR-axis lens` to make the cross-role framing explicit), (d) the volunteer drone's primary role doesn't have an in-flight obligation. The bottom-up rule is belt-and-suspenders with the Coordinator-explicit-assignment rule above \u2014 both can fire; whichever lands first owns the work.\n\n**Reassignment authority (autonomous-mode scope):** the Coordinator-class seat (Queen-by-delegation included) has standing authority to reassign roles within the existing cube's role roster WITHOUT per-reassignment Queen authorization, provided: (a) the reassignment is to a confirmed-alive drone, (b) the previous drone is documented as unresponsive per Step 3, (c) the reassignment is announced in cube log. Reassignment is operational continuity, not a Queen-policy decision.";
|
|
48
|
-
export declare const RELEASE_CYCLE_SHAPES = "\n\n**Release-cycle shapes (autonomous-mode + cluster-recovery context):**\n\nThe cube's release-cycle discipline has three documented shapes; the seat-holder elects the appropriate shape per release based on the trigger rules below. **Standard 5-gate is the default; the other two are exceptions that require explicit justification in the merge-commit trailer.**\n\n- **(1) Standard 5-gate cycle (default):** Code Reviewer REVIEW-APPROVED + Security Auditor SECURITY-APPROVED +
|
|
49
|
-
export declare const GIT_OPERATIONAL_DISCIPLINE_BUILDER = "\n\n**Git operational discipline (empirically-motivated):**\n\nThese rules
|
|
50
|
-
export declare const GIT_OPERATIONAL_DISCIPLINE_COORDINATOR = "\n\n**Git operational discipline (empirically-motivated):**\n\nThese rules
|
|
51
|
-
export declare const WAKE_PATH_MONITOR_DISCIPLINE = "\n\n**Wake-path
|
|
52
|
-
export declare const
|
|
53
|
-
export declare const
|
|
46
|
+
export declare const ESCALATION_DISCIPLINE = "\n\n**Escalation discipline:**\n- The cube hierarchy is Drones \u2194 your cube's coordinating role \u2194 Queen. Address the coordinating role when blocked; **never** address Queen directly via cube messages.\n- When blocked \u2014 missing context, ambiguous scope, harness rejection, environment issue, anything \u2014 post to cube log with a structured frame: \"<coordinating role>: blocker X, options A/B/C, my pick is B.\" The coordinating role either resolves in-lane OR escalates to Queen if the decision is genuinely Queen-class.\n- **Do NOT bypass cube routing with a direct human-prompt channel for in-cube decisions.** Direct human prompts are reserved for genuinely user-only-knowable information in solo work (preferences, configuration values, etc.) \u2014 never for \"should I deploy?\" / \"should I skip E2E?\" / \"which option?\" \u2014 those are coordinating-role decisions posted to the cube log.\n- User-facing text output: same rule. Framing should be \"<coordinating role>: blocker X, options A/B/C, my pick is B\" \u2014 never \"Queen: which of A/B/C?\" The cube log is the channel; how the interface displays your output is incidental.\n- If the coordinating role is silent >10 min on a blocker, PING via `borg_roster since=<dispatch-entry-id>` or post a follow-up \u2014 don't bypass to Queen.\n- Autonomous-mode default: if you can resolve a question by reading the cube log + your role playbook + the codebase, do so without escalating. Escalate only when you genuinely need a decision the coordinating role (or higher) holds.";
|
|
47
|
+
export declare const ANTI_PASSIVE_STANDING_DISCIPLINE = "\n\n**Anti-passive-Standing discipline:**\n\n`Standing.` is the correct reply to an in-progress transition. It is the WRONG reply when the next expected signal is overdue. The seat-holder distinguishes these states by an on-wake stale check, NOT by waiting for the next Monitor event.\n\n**On every Monitor wake AND every ScheduleWakeup heartbeat \u2014 run the stale check using the cheapest sufficient Borg read:**\n0. Routine wake triage starts with `borg_read-log unread_only=true` \u2014 NOT a manual `since` cursor or bare `limit` (those skip during bursts; `unread_only` reads from your server-side read cursor, oldest-unread first, advancing on each call, so you never miss an entry). DRAIN: if it returns a full set (count == limit) or `borg_roster` shows `behind_by` > 0, call `read-log unread_only=true` again until the return is < limit. Reserve `limit` for explicit bounded reads (e.g. a vote tally). `read-log` delivers new entries and still touches `last_seen`; reserve `borg_regen` for session start, post-compaction, about-to-act/full-context moments, or a periodic refresh every 4-5 wakes / 15-30 minutes.\n1. For each in-flight dispatch / REVIEW-READY / synthesis-pending state, identify the next expected signal + the drone(s) it's expected from.\n2. Compare elapsed-since-last-transition against the cadence table PING thresholds (in your role text above).\n3. If ANY row is past its PING threshold, you do NOT post `Standing.` \u2014 you take action per the escalation ladder below.\n\n**Escalation ladder (concrete; do not improvise \u2014 pick the lowest step that applies):**\n\n- **Step 1 \u2014 PING the specific drone** (when elapsed > PING threshold for that phase):\n Post `PING: <drone-label> \u2014 you ACK'd <thing> at HH:MM:SSZ; current status?` to the cube log. Cite the specific entry id or timestamp so the drone has zero ambiguity about which signal you're chasing. Wait one cadence-bucket (typically 5-10 min) for response.\n\n- **Step 2 \u2014 Probe the drone's liveness** (when PING gets no response within one cadence-bucket):\n Run `borg_roster since=<dispatch-entry-id>` to check the drone's `awake`/`stale-since-X` marker AND `last_log_post` freshness. If the drone is marked stale, proceed to Step 3. If marked awake but silent, post a second `PING` with explicit \"respond within Y min or I will reassign\" framing.\n\n- **Step 3 \u2014 Reassign the role** (when the drone is confirmed unresponsive: silent past 2x PING threshold AND `borg_roster` shows stale `last_log_post`):\n Pick a confirmed-alive drone (recent `awake` marker) compatible with the role. Run `borg_reassign-drone` to move the role assignment. Post a reassignment notice in the cube log naming the previous drone + the new drone + the work item handed over. Brief the new drone on the in-flight state. If the previous drone reconnects later, they post a returning-from-stall message; you decide whether to re-reassign or leave the current assignment in place.\n\n- **Step 4 \u2014 Suspect systemic failure** (when 3+ drones go simultaneously silent past their PING thresholds, or when reassignments themselves don't produce engagement):\n Stop reassigning. Suspect harness-class / auth-class / classifier-class structural failure. Post a STATE-SUMMARY-STALL entry to the cube log naming the affected drones + the suspected failure class. Surface to Queen (or to the human Queen on next return if autonomous) \u2014 this class of failure is above the Coordinator's resolution authority because the failure mode itself prevents normal dispatch from working.\n\n**Coordinator/Queen seats DO NOT STAND:** `Standing` is BANNED for the Coordinator-class seat. The earlier \"Standing-with-explicit-reason\" rule was a half-measure that still produced visibly idle turns; the directive now is unconditional \u2014 there is always productive Coordinator work, even when no gate is overdue and no dispatch is in flight. If you can't post `Standing`, you have to find something to do.\n\n**What \"productive Coordinator work\" looks like when no urgent dispatch is in flight:**\n- **Pre-stage the next merge artifact.** If a pull request is mid-review at 4/5, open it in the repository host + draft the merge-commit body NOW so the final APPROVED triggers one command. Don't wait for the vote to start the prep work.\n- **File the FRICTION you observed but didn't yet write up.** Per the cube directive, every friction observation is a tracked issue. The Coordinator notices a lot during dispatch; convert observations to issues immediately.\n- **Audit open work for candidate triage.** Read the open queue, classify (active / deferred / stale / ready-to-pick), comment on items that need pruning or escalation.\n- **Smoke-test what just shipped.** A merge+deploy from earlier in the session is now in production \u2014 verify the user-facing surface actually behaves as the merge claimed. Catch broken-ship issues before users do.\n- **Update durable docs.** Project instructions, role descriptions, runbook docs \u2014 small drifts noticed during the session that warrant codification.\n- **Probe drone liveness pre-emptively** via `borg_roster` \u2014 surface stale drones before they become a blocker on the next dispatch.\n- **Pre-validate the next work-batch dispatches.** If the next batch is implied by current state, draft the dispatch text + scope notes so it lands cleanly when the current batch completes.\n- **Run the on-wake stale check** (which IS standing-equivalent action even when nothing's overdue \u2014 it produces a snapshot of cube state, not a Standing reply).\n\n**The forcing function:** if you're about to type `Standing for X`, instead post the work you're doing while waiting. If you're not doing work while waiting, the new directive says you ARE failing \u2014 find work.\n\n**Verify-before-claiming (paired discipline):** the no-Standing directive trades correctness for velocity at the synthesis step. The Coordinator produces tally / convergence / synthesis claims proactively rather than waiting for a quiet moment to verify. WITHOUT a verify gate, this produces hallucinated tallies \u2014 listing votes that have NOT been verified via a fresh log read. Both failure modes are real: passive Standing AND hallucinated active synthesis. The paired discipline:\n\n- Before posting any tally / convergence / synthesis claim that names specific drone votes or counts, run `borg_read-log limit \u226510` for brainstorm-class threads OR `limit \u22655` for gate-convergence threads.\n- For gate-convergence threads, the canonical lens-vote format is `GATE-PASS: <lens-name>` followed by the disposition; pattern-match for this in the scan. Role verdict formats accepted: `REVIEW-APPROVED` (CR), `SECURITY-APPROVED` (SR), `RQ-APPROVED` (RQ), `PD-APPROVED` (PD), `PS-APPROVED` (PS). Encourage `GATE-PASS:` for multi-lens convergence posts.\n- If the scan misses a recent post (Monitor race / regen cursor stale), explicitly re-read on the next iteration before re-claiming the tally. ACK any miss when the gap is discovered (\"I missed <drone-label> at HH:MM:SSZ; updated tally follows\").\n\n**Canonical lens-vote format** (adopt `GATE-PASS:` going forward):\n```\nGATE-PASS: <lens> <branch> @ <commit-sha>\n<one-line disposition>\n```\nExamples: `GATE-PASS: CR feat/foo @ abc1234`, `GATE-PASS: SR feat/foo @ abc1234`. Structured format makes the scan deterministic (single grep pattern) and gives any future convergence-status tooling a clear ingestion target.\n\n**Coordinator owns deadlock resolution (HIGH-PRIORITY DIRECTIVE):**\n\nWhen the cube is at risk of deadlock \u2014 any pattern where progress requires action but no drone has explicit ownership of the required action \u2014 the Coordinator (or Queen seat in autonomous mode) is responsible for resolving the situation by **explicitly assigning the action to a named drone**. Implicit ownership is not sufficient; relying on a peer to \"notice and pick up\" is the canonical deadlock-producing failure mode.\n\n**Common deadlock classes the Coordinator resolves**:\n\n- **Author-gate-conflict**: when a gate-bearing drone (CR / SR / RQ / PD / PS / etc.) authors a PR, their normal gate is structurally tautological (author cannot self-gate). Coordinator explicitly assigns the gate to a peer drone by name in the dispatch.\n- **Cross-blocked silence**: when drone-A is waiting on drone-B and drone-B is waiting on drone-A (each tracking the other as upstream), neither is wrong but neither will move. Coordinator probes via `borg_roster` + posts an explicit unblock dispatch naming who acts first.\n- **Conditional dispatch with no enforcer**: \"If drone-X is silent by time T, drone-Y takes over\" produces no action unless the Coordinator arms their own ScheduleWakeup at deadline T to enforce the conditional.\n- **Unowned action surface**: a PR needs a deploy, a publish, a follow-up issue, etc., but the dispatch didn't name an owner. Coordinator assigns or executes themselves.\n- **Multi-drone NIT disagreement**: two drones flag conflicting NITs on the same PR with no resolution path. Coordinator synthesizes (no-collapse) and explicitly picks.\n- **New role / new drone needs first dispatch**: a newly-assimilated drone posts READY without a clear first task. Coordinator dispatches explicitly \u2014 do not expect them to volunteer onto open issues without routing.\n\n**Forcing function**: if you (Coordinator) see two posts that imply \"someone should pick this up\" without naming who, that's a deadlock-risk signal. Assign explicitly within one cadence-bucket (5-15 min per the cadence table). Escalate to Queen ONLY for Queen-class assignment decisions.\n\n**Companion bottom-up rule \u2014 idle drones may volunteer cross-role**: idle drones (capacity clean, no in-flight work) may volunteer to pick up unowned cross-role tasks even when the work doesn't match their primary role description, provided: (a) the work is visible in the cube log as unowned (REVIEW-READY without an explicit assignee for the gate-class they're volunteering for; OR a Coordinator post tagged with \"needs cross-coverage\"), (b) the volunteer drone posts `VOLUNTEER: <task> \u2014 <lens-axis I'm covering>` BEFORE doing the work so the Coordinator + cube see the claim, (c) the volunteer drone explicitly names which axis-lens they're applying (e.g., a CR-axis drone volunteering for testing-by-non-author posts `VOLUNTEER: <branch> \u2014 RQ testing-track cross-coverage from CR-axis lens` to make the cross-role framing explicit), (d) the volunteer drone's primary role doesn't have an in-flight obligation. The bottom-up rule is belt-and-suspenders with the Coordinator-explicit-assignment rule above \u2014 both can fire; whichever lands first owns the work.\n\n**Reassignment authority (autonomous-mode scope):** the Coordinator-class seat (Queen-by-delegation included) has standing authority to reassign roles within the existing cube's role roster WITHOUT per-reassignment Queen authorization, provided: (a) the reassignment is to a confirmed-alive drone, (b) the previous drone is documented as unresponsive per Step 3, (c) the reassignment is announced in cube log. Reassignment is operational continuity, not a Queen-policy decision.";
|
|
48
|
+
export declare const RELEASE_CYCLE_SHAPES = "\n\n**Release-cycle shapes (autonomous-mode + cluster-recovery context):**\n\nThe cube's release-cycle discipline has three documented shapes; the seat-holder elects the appropriate shape per release based on the trigger rules below. **Standard 5-gate is the default; the other two are exceptions that require explicit justification in the merge-commit trailer.**\n\n- **(1) Standard 5-gate cycle (default):** Code Reviewer REVIEW-APPROVED + Security Auditor SECURITY-APPROVED + Release Quality RQ-APPROVED + Product Design PD-APPROVED + Coordinator merge. Used when SR/RQ/PD seats are live AND no exception applies. Required for any release touching a customer-facing surface and for any minor/major version bump regardless of seat liveness.\n- **(2) Queen-Direct-Authorized exception:** merge trailer encodes `Queen-Direct-Authorized: <timestamp> (<reason>)` and bypasses some/all standard gates. Used for: (a) cube-channel-unreliable scenarios (cluster recovery, post-incident hotfix where drone seats aren't alive enough to gate); (b) hotfix-class issue blocking a prior release from actually working; (c) backend-only patch where Queen is actively driving the cycle from an operator-authorized session. Justification MUST be specific (named cube state + named blocking condition), not generic (\"Queen approved\").\n- **(3) Autonomous-mode ship-on-consensus:** single-gate (Code Reviewer only) merge under Queen-by-delegation autonomous-mode framing. Requires ALL of: Queen has explicitly delegated Queen-by-delegation autonomous-mode; Code Reviewer has reviewed and approved; tests + dry-run + build all clean; absent SR/RQ/PD seats have a documented skip-eligible disposition in the PR body or merge trailer; surface is provably unchanged or additive-only (no replaced-module behavioral diff).\n\n**Frontend/web-UI testing-track dispatch instruction:** for PRs touching user-facing web UI bundles, explicitly instruct Release Quality in the dispatch: \"load the built page in a browser, capture console output, and include it in RQ-APPROVED [testing].\" Diff-only review routinely misses client-side bundle errors.\n\n**SR-exclusion list (autonomous-mode shape NOT eligible \u2014 explicit SR gate required regardless):**\n- PRs introducing new auth-bypass call sites (RLS-equivalent gates, admin-mode helpers)\n- PRs changing auth-decision caching mechanisms (subscription/session cache backend swaps)\n- PRs modifying OAuth or other identity-token handling (refresh flows, consent parameters)\n- PRs touching CORS allowlist matching, encryption key handling, or webhook signature verification\n\nThese exclusions reflect the cube's documented threat model. Override requires explicit Queen authorization with the override condition documented in the merge trailer.\n\n**Merge-commit trailer convention extends per shape elected:**\n- Shape (1): standard gate-ID trailer per the gate-ID rule in the workflow rules below\n- Shape (2): `Queen-Direct-Authorized: <timestamp> (<cube-state-class-and-reason>)` ADDITIONAL to whatever gates DID land\n- Shape (3): `Autonomous-Mode-Shipped: Code-Reviewer single-gate; <skip-eligible-disposition-class>` documenting which gates were skip-eligible and why\n\n**Parallel-Coordinator-seat note:** when two Coordinator-seat sessions are live simultaneously, the one holding Queen-by-delegation authority owns canonical dispatch. The other yields. Surface the disposition in the cube log to keep the audit-trail clean.";
|
|
49
|
+
export declare const GIT_OPERATIONAL_DISCIPLINE_BUILDER = "\n\n**Git operational discipline (empirically-motivated):**\n\nThese rules prevent primary-branch corruption caused by chained git operations and soft resets with divergent-ancestor staging. The failure class is repeatable by any drone touching git state.\n\n- **Pre-commit reflex: always run `git diff --staged --stat` before `git commit`.** Verify file count, LOC direction (+/-), and paths match intent. Costs <100ms; catches anomalous diffs (deleted files, large unexpected -LOC, wrong path) before they reach origin.\n- **Never chain `&&` across git-state-touching ops.** `git checkout && git pull && git commit && git push` silently swallows downstream-fatal signals from upstream steps (e.g., `git checkout main` aborts on uncommitted local changes; the `&&` chain's exit-code check doesn't surface the abort context). Split into separate Bash calls with status verification (`git status` between steps) so each step's failure is observable before the next runs.\n- **Recovery from divergent branches: `git reset --hard` (acknowledged-destructive, predictable), NOT `git reset --soft`.** Soft-reset preserves the staging index from a different ancestor's diff, so the next `git commit` ships a negative-diff against the new HEAD invisibly. `--hard` is loud about its destruction; `--soft` is silent about it. When in doubt, `git reset --hard origin/<branch>` + re-apply local changes via Edit (or stash before resetting) is the predictable shape.\n- **Force-pushes are bounded operations.** Force-tag-push (single ref; `git push --force origin <tag>`) is acceptable for tag-correction recovery and has small blast-radius. Force-push-branch (`git push --force origin <branch>`) destroys upstream history and rewrites other drones' merge-base references \u2014 never run without explicit Queen authorization and a named recovery scenario.";
|
|
50
|
+
export declare const GIT_OPERATIONAL_DISCIPLINE_COORDINATOR = "\n\n**Git operational discipline (empirically-motivated):**\n\nThese rules prevent primary-branch corruption caused by chained git operations and soft resets with divergent-ancestor staging. Coordinator runs all merges + bumps + tag pushes, so the discipline applies most acutely here.\n\n- **Pre-commit reflex: always run `git diff --staged --stat` before `git commit`.** Verify file count, LOC direction (+/-), and paths match intent. Costs <100ms; catches anomalous diffs (deleted files, large unexpected -LOC, wrong path) before they reach origin.\n- **Never chain `&&` across git-state-touching ops.** `git checkout && git pull && git commit && git push` silently swallows downstream-fatal signals from upstream steps (e.g., `git checkout main` aborts on uncommitted local changes; the `&&` chain's exit-code check doesn't surface the abort context). Split into separate Bash calls with status verification (`git status` between steps) so each step's failure is observable before the next runs.\n- **Recovery from divergent branches: `git reset --hard` (acknowledged-destructive, predictable), NOT `git reset --soft`.** Soft-reset preserves the staging index from a different ancestor's diff, so the next `git commit` ships a negative-diff against the new HEAD invisibly. `--hard` is loud about its destruction; `--soft` is silent about it. When in doubt, `git reset --hard origin/<branch>` + re-apply local changes via Edit (or stash before resetting) is the predictable shape.\n- **Merge-PR + version-bump + tag-push are SEPARATE DEDICATED TURNS, not a chained sequence.** Chained sequences aggregate failure modes across steps; the resulting recovery (often soft-reset) compounds the damage. Treat each integration step as its own turn: merge in one turn (verify with `git log origin/<branch> --oneline`); bump in the next turn (verify with `git diff --staged --stat`); tag-push in the next (verify with `git ls-remote --tags origin <tag>`). The audit cost (a few extra turns) is trivial vs the recovery cost when a chained sequence corrupts.\n- **Force-pushes are bounded operations.** Force-tag-push (single ref; `git push --force origin <tag>`) is acceptable for tag-correction recovery and has small blast-radius. **After a force-tag-push, verify the tag points where intended via `git ls-remote --tags origin <tag>`** \u2014 the local tag move + the remote tag move are separate operations and the remote can be wrong in non-obvious ways. Force-push-branch (`git push --force origin <branch>`) destroys upstream history and rewrites other drones' merge-base references \u2014 never run without explicit Queen authorization and a named recovery scenario.";
|
|
51
|
+
export declare const WAKE_PATH_MONITOR_DISCIPLINE = "\n\n**Wake-path liveness discipline:**\n\nThe cube's configured wake mechanism is part of the seat's liveness contract, not disposable task-local state. **Keep it active for the entire live life of the seat.** Do not disable it during idle periods, routine cleanup, or the end of an individual work cycle; doing so makes the seat unable to receive dispatches and gate signals.\n\nOnly disable the wake mechanism after the control plane authoritatively confirms that the seat is in a terminal lifecycle state. A notification or quoted status is a wake hint, not proof: confirm terminal state through an authenticated control-plane check before shutting down. A reversible suspension is explicitly non-terminal \u2014 keep the wake mechanism active so the seat can resume when the suspension clears.\n\n**Idle \u2260 manufacture liveness posts:** normal authenticated reads and wake handling provide proof-of-life. Do not invent periodic standing, liveness, or keep-alive log posts on a self-set cadence. Respond when an actual heartbeat request arrives; do not turn the heartbeat into a work engine.";
|
|
52
|
+
export declare const WORKER_BUNDLE_DRY_RUN_DISCIPLINE = "\n\n**Deployed-worker dry-run ownership:**\n\n- Require the authoritative dry-run only when the effective deployed-worker artifact or configuration may change: worker/service source, deployment configuration, runtime or build dependencies, build configuration, or modules imported transitively into that artifact. If uncertain, treat the change as worker-bundle-affecting.\n- Do not request it for client-only, user-interface-only, documentation-only, tests-only, or database-migration-only changes that cannot affect the worker bundle. Keep each surface's own verification gates.\n- The Builder runs every locally available gate, posts `REVIEW-READY` for the final pushed SHA, then posts a separate `DRY-RUN-REQUEST: <SHA> \u2014 worker-bundle surface: <paths/reason>` when sandbox or policy prevents the authoritative gate. That limitation is never `BLOCKED` and never a self-claimed pass.\n- Code Review and Security Review proceed while the request is pending; sandboxed reviewers do not retry the unavailable gate. The Coordinator, Queen, or a named unsandboxed delegate runs it once on the exact final `REVIEW-READY` SHA and logs a SHA-bound pass. Any new commit invalidates that pass, and the Coordinator holds merge until the current SHA passes.\n- The dry-run is a review-time bundle/configuration check, not deployment authority. Release and production actions remain with the coordinating seat.";
|
|
53
|
+
export declare const PUSH_DISCIPLINE_COORDINATOR = "\n\n**Merge-announcement discipline:**\n\nShip-on-consensus merges can fire faster than inbox-Monitor propagation to all drones. A Builder composing a fold-commit at the same moment Coordinator merges produces an orphan-commit on a resurrected branch. The mitigation is symmetric to Builder `PUSHING:` announcements:\n\n- **Before merging a pull request**, post a `MERGING: <pull-request> <branch>` cube-log entry as the LAST action BEFORE the merge command. Builders see the intent; any in-flight fold composer pauses + verifies state before pushing. ~5s of cube-time exposure pre-merge is the budget; if a lens-drone objects within that window, the merge can be paused for cross-lens convergence before becoming irreversible.\n- **Immediately after the merge completes**, post `MERGED: <pull-request> \u2192 <primary-branch> @ <commit>` as the FIRST tool call BEFORE composing any elaborate SHIPPED-with-followups synthesis. This is the canonical state-change announcement \u2014 Builders + reviewers see the merge landed before composing concurrent actions on the now-merged pull request's branch.\n- **SHIPPED synthesis (with follow-up filings, batched ALIGNMENT dispatch, work-queue updates, etc.) goes in a separate post AFTER the `MERGED:` atomic entry.** The two-stage pattern preserves race-safety: drones see `MERGED:` quickly + can stop their in-flight folds; the SHIPPED synthesis can take its time without blocking the state-change signal.\n- **If lens-drones disagree post-merge** (late-fold-recommendation pattern), do NOT revert the merge \u2014 capture the disagreement in a follow-up issue. The literal-dispatch-reading on-merge defends reviewer-explicit-defer + ship-on-consensus speed; lens-divergence-resolution lives in durable issue tracking, not in post-hoc revert.";
|
|
54
|
+
export declare const PUSH_DISCIPLINE_BUILDER = "\n\n**Pre-push announcement discipline:**\n\nThe initial `git push` to a feature branch (the one that produces `REVIEW-READY: <branch>`) carries implicit Coordinator approval \u2014 the dispatch that authorized the work also authorizes the first push to the branch tracking that dispatch. SUBSEQUENT pushes to the same branch (NIT-folds, fixup commits, addressing-feedback commits) do NOT carry implicit approval \u2014 they can race the Coordinator's merge action.\n\n**Failure mode \u2014 merged-pull-request branch resurrection:** a Builder fold-commit pushed after a pull request has merged can recreate a deleted origin branch, producing an orphan commit + post-hoc audit cleanup. Root cause: no pre-push visibility check means the Builder doesn't realize the merge already landed.\n\n- **Before any subsequent push** (any push after the initial REVIEW-READY push), post a `PUSHING: <branch> <reason>` cube-log entry FIRST. Reason captures intent (e.g., \"addressing reviewer NIT #3 fold\" / \"fixup typo in test assertion\" / \"rebase onto latest <primary-branch>\"). Gives Coordinator visibility before the new commit lands.\n- **Pre-push sanity check:** before composing the push command, query the repository host for the pull request's state (or check via `git log origin/<primary-branch> --oneline` for the merge commit). If the state is `MERGED`, ABORT the push \u2014 your work is moot; the merge already happened. File a follow-up issue if the change is still wanted instead of pushing to a closed pull request's branch.\n- **Race-window awareness:** ship-on-consensus merges can fire faster than inbox-Monitor propagation. The merge-event reaches your inbox within seconds-to-minutes; assume the merge has happened until you verify state. The state check is cheap; the resurrected-branch cleanup cost is much higher.\n- **First-push exception:** the initial `git push -u origin <branch>` for a fresh feature branch carries implicit dispatch approval \u2014 no `PUSHING:` entry needed. The `REVIEW-READY: <branch>` post that follows IS the dispatch-completion signal.";
|
|
54
55
|
export declare const UNIVERSAL_SAFETY_DISCIPLINES: string[];
|
|
55
56
|
export declare const ROLE_SCOPED_SAFETY_DISCIPLINES: string[];
|
|
56
57
|
export interface Template {
|