buildkeel 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +49 -0
  2. package/README.md +37 -3
  3. package/THIRD-PARTY-NOTICES +231 -0
  4. package/antigravity/LICENSE +49 -0
  5. package/antigravity/THIRD-PARTY-NOTICES +231 -0
  6. package/antigravity/bin/bk-launch +38 -0
  7. package/antigravity/bin/bk-launch.cmd +50 -0
  8. package/antigravity/dist/hooks/main.js +20 -0
  9. package/antigravity/dist/server/main.js +358 -0
  10. package/antigravity/package.json +8 -0
  11. package/antigravity/plugin.json +6 -0
  12. package/antigravity/rules/buildkeel.md +72 -0
  13. package/antigravity/skills/bk-adhoc/SKILL.md +49 -0
  14. package/antigravity/skills/bk-approve/SKILL.md +50 -0
  15. package/antigravity/skills/bk-build/SKILL.md +50 -0
  16. package/antigravity/skills/bk-capture/SKILL.md +94 -0
  17. package/antigravity/skills/bk-done/SKILL.md +56 -0
  18. package/antigravity/skills/bk-impact/SKILL.md +46 -0
  19. package/antigravity/skills/bk-init/SKILL.md +34 -0
  20. package/antigravity/skills/bk-migrate/SKILL.md +19 -0
  21. package/antigravity/skills/bk-new/SKILL.md +99 -0
  22. package/antigravity/skills/bk-onboard/SKILL.md +116 -0
  23. package/antigravity/skills/bk-start/SKILL.md +38 -0
  24. package/antigravity/skills/bk-stats/SKILL.md +38 -0
  25. package/antigravity/skills/bk-status/SKILL.md +16 -0
  26. package/antigravity/templates/adhoc.md +15 -0
  27. package/antigravity/templates/bug.md +33 -0
  28. package/antigravity/templates/design.md +47 -0
  29. package/antigravity/templates/epic.md +30 -0
  30. package/antigravity/templates/idea.md +34 -0
  31. package/antigravity/templates/story.md +30 -0
  32. package/antigravity/templates/task.md +21 -0
  33. package/antigravity/templates/test-plan.md +29 -0
  34. package/cli.mjs +220 -0
  35. package/package.json +14 -9
  36. package/bin/buildkeel.js +0 -3
@@ -0,0 +1,50 @@
1
+ @echo off
2
+ rem Starts a BuildKeel component after checking for Node.js 20 or later.
3
+ rem Usage: bk-launch <server|hook> [args...]
4
+ rem BK_LAUNCH_DIST overrides the directory holding the built components.
5
+ setlocal EnableDelayedExpansion
6
+
7
+ set "REQUIRED_MAJOR=20"
8
+
9
+ set "TARGET=%~1"
10
+ if /I "%TARGET%"=="server" (set "ENTRY=server\main.js" & goto :target_ok)
11
+ if /I "%TARGET%"=="hook" (set "ENTRY=hooks\main.js" & goto :target_ok)
12
+ echo usage: bk-launch ^<server^|hook^> [args...] 1>&2
13
+ exit /b 64
14
+
15
+ :target_ok
16
+ if defined BK_LAUNCH_DIST (set "DIST=%BK_LAUNCH_DIST%") else (set "DIST=%~dp0..\dist")
17
+
18
+ set "ARGS="
19
+ :collect
20
+ shift
21
+ if "%~1"=="" goto :check
22
+ set ARGS=!ARGS! "%~1"
23
+ goto :collect
24
+
25
+ :check
26
+ where node >nul 2>nul
27
+ if errorlevel 1 (
28
+ set "REASON=Node.js was not found on your PATH."
29
+ goto :fail
30
+ )
31
+ set "VERSION="
32
+ for /f "delims=" %%v in ('node -p "process.versions.node" 2^>nul') do set "VERSION=%%v"
33
+ if not defined VERSION (
34
+ set "REASON=Node.js could not be run."
35
+ goto :fail
36
+ )
37
+ for /f "tokens=1 delims=." %%m in ("%VERSION%") do set "MAJOR=%%m"
38
+ set /a MAJOR_NUM=MAJOR 2>nul
39
+ if %MAJOR_NUM% LSS %REQUIRED_MAJOR% (
40
+ set "REASON=Found Node.js %VERSION%."
41
+ goto :fail
42
+ )
43
+
44
+ node "%DIST%\%ENTRY%" %ARGS%
45
+ exit /b %ERRORLEVEL%
46
+
47
+ :fail
48
+ echo BuildKeel needs Node.js %REQUIRED_MAJOR% or later. %REASON% 1>&2
49
+ echo Install it from https://nodejs.org or with your version manager (for example "nvm install %REQUIRED_MAJOR%"), then start a new session. 1>&2
50
+ exit /b 1
@@ -0,0 +1,20 @@
1
+ import { createRequire as __bkCreateRequire } from 'node:module'; const require = __bkCreateRequire(import.meta.url);
2
+ import{appendFileSync as re,readFileSync as ie}from"node:fs";var dt=["claude-code","antigravity"],I=t=>dt.includes(t);function y(t,n){return t==="antigravity"?`/bk-${n}`:`/bk:${n}`}function R(t,n){return t.replace(/\{\{bk:([a-z][a-z-]*)\}\}/g,(e,o)=>y(n,o))}import{isAbsolute as $,relative as ht,resolve as D}from"node:path";import{existsSync as N}from"node:fs";import{dirname as pt,join as j,resolve as ft}from"node:path";var gt=".buildkeel.yaml";function w(t){let n=ft(t);for(;;){if(N(j(n,gt)))return n;if(N(j(n,".git")))return null;let e=pt(n);if(e===n)return null;n=e}}var K=["write_to_file","replace_file_content","multi_replace_file_content"],ge=K.join("|");var mt={decision:"allow"},B={decision:"ask"},C=(t,n)=>{let e=ht(t,n);return e===""||!e.startsWith("..")&&!$(e)};function b(t,n){let e=(t.workspacePaths??[]).filter(r=>typeof r=="string"&&r!==""),o=n?[...e.filter(r=>C(r,n)),...e.filter(r=>!C(r,n))]:e;return o.find(r=>w(r)!==null)??o[0]??process.cwd()}var F={parse(t,n){let e=t??{};switch(n[0]){case"PreInvocation":return e.conversationId?{kind:"prompt",cwd:b(e),conversation:e.conversationId,newMessage:e.invocationNum===0,transcript:e.transcriptPath??null}:{kind:"ignored"};case"PreToolUse":case"PostToolUse":{let o=e.toolCall?.name??"",r=e.toolCall?.args?.TargetFile,i=K.includes(o)&&typeof r=="string"&&r!==""?r:null;if(n[0]==="PostToolUse"){if(!i||e.error)return{kind:"ignored"};let s=b(e,$(i)?i:void 0);return{kind:"after-edit",cwd:s,tool:o,files:[D(s,i)],...e.conversationId?{deferTo:e.conversationId}:{}}}let c=b(e,i&&$(i)?i:void 0),a=[...e.workspacePaths??[],...e.artifactDirectoryPath?[e.artifactDirectoryPath]:[]].filter(s=>typeof s=="string"&&s!=="");return{kind:"before-edit",cwd:c,tool:o,files:i?[D(c,i)]:[],folders:a}}default:return{kind:"ignored"}}},render(t,n){if(n.kind==="prompt"){let e=t.context?{injectSteps:[{ephemeralMessage:t.context}]}:{};return{stdout:JSON.stringify(e),exitCode:0}}if(n.kind==="before-edit"){let e=n.files.length>0&&n.files.every(r=>(n.folders??[]).some(i=>C(i,r))),o=t.block?{decision:"deny",reason:t.block}:e?mt:B;return{stdout:JSON.stringify(o),exitCode:0}}return{stdout:"{}",exitCode:0}},failed:t=>({stdout:JSON.stringify(t[0]==="PreToolUse"?B:{}),exitCode:0})};var P={Edit:"file_path",Write:"file_path",MultiEdit:"file_path",NotebookEdit:"notebook_path"},me=Object.keys(P).join("|"),kt={startup:"startup",resume:"resume",clear:"clear",compact:"compact",fork:"resume"},U={parse(t){let n=t??{},e=n.cwd??process.cwd();switch(n.hook_event_name){case"SessionStart":{let o=kt[n.source??"startup"]??"startup";return{kind:"session-start",cwd:e,reason:o}}case"PreToolUse":case"PostToolUse":{let o=n.tool_name??"",r=P[o],i=r?n.tool_input?.[r]:void 0;return typeof i!="string"?{kind:"ignored"}:{kind:n.hook_event_name==="PreToolUse"?"before-edit":"after-edit",cwd:e,tool:o,files:[i]}}default:return{kind:"ignored"}}},render(t,n){if(n.kind==="session-start")return{stdout:t.context??"",exitCode:0};if(n.kind==="before-edit"&&(t.block||t.context)){let e={hookSpecificOutput:{hookEventName:"PreToolUse",...t.block?{permissionDecision:"deny",permissionDecisionReason:t.block}:{},...t.context?{additionalContext:t.context}:{}}};return{stdout:JSON.stringify(e),exitCode:0}}return n.kind==="after-edit"&&t.context?{stdout:JSON.stringify({hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:t.context}}),exitCode:0}:{stdout:"",exitCode:0}},failed:()=>({stdout:"",exitCode:1})};import{existsSync as xe,readFileSync as yt,writeFileSync as we}from"node:fs";import{join as L}from"node:path";var d=".buildkeel",xt="hook-cache.json",wt="context.md",J=t=>L(t,d,wt);function vt(t){return L(t,d,xt)}function M(t){try{return JSON.parse(yt(vt(t),"utf8"))}catch{return null}}var Se=`${d}/`;import{appendFileSync as bt,closeSync as $t,fstatSync as Ct,mkdirSync as z,openSync as _t,readFileSync as V,readSync as Et,renameSync as Tt,rmSync as Ot,statSync as At,writeFileSync as It}from"node:fs";import{homedir as Rt}from"node:os";import{join as S}from"node:path";import{readFileSync as St}from"node:fs";function _(t,n){let e=[{key:"setup",text:"BuildKeel is set up in this repository. Converse as you would without it: follow the user's lead, explore ideas, options and code freely, and leave BuildKeel's artifacts, IDs and commands out of it until the user runs a BuildKeel command, asks you to change code, or asks to move work forward. BuildKeel's instructions then say how to go on.",fingerprint:""}];if(t.activeUnit){let o=t.activeBranch?` on branch ${t.activeBranch}`:"";e.push({key:"unit",text:`Active unit: ${t.activeUnit}${o}.`,fingerprint:`${t.activeUnit}${o}`})}else t.untrackedSince?e.push({key:"unit",text:`No active unit in this working tree: the user chose to work without one here since ${t.untrackedSince}, so changes made now belong to no unit. Starting a unit with ${y(n,"start")} <ID> ends this.`,fingerprint:`untracked:${t.untrackedSince}`}):e.push({key:"unit",text:"No unit is active in this working tree.",fingerprint:""});if(e.push({key:"rules",text:"Read and change the spec tree only through the BuildKeel tools, never by editing its files.",fingerprint:""}),t.stages){let o=(t.stageExamples??[]).map(i=>`\`${i}\``),r=o.length>1?`${o.slice(0,-1).join(", ")} or ${o.at(-1)}`:o[0]??"";e.push({key:"stages",text:`This spec tree's stages, as the team names them: ${t.stages}. Use these names with the user, in each command's help, questions and output; BuildKeel's tools accept them as types, and the usual names too.`+(r?` Examples of what to draft, in the team's words: ${r}; use these in place of a command's usual examples.`:""),fingerprint:`${t.stages}|${o.join(",")}`})}return e}function Ht(t,n,e){if(!n.activeUnit)return null;try{return R(St(J(t),"utf8").trimEnd(),e)}catch{return null}}function v(t,n,e,o){let r=Ht(t,n,e),i=["BuildKeel:"];for(let c of _(n,e)){let a=c.key==="unit"&&n.activeUnit?r?o?" Its context is loaded again below.":" Its context follows.":" BuildKeel has no context for it; call the BuildKeel get_context tool to see why.":"";i.push(`- ${c.text}${a}`)}return r&&i.push("",r),i.join(`
3
+ `)}var W=({event:t,codeRoot:n,cache:e,host:o})=>t.kind!=="session-start"?null:{context:v(n,e,o,t.reason==="compact")};var q=(t,n,e)=>S(t,d,"conversations",`${n.replace(/[^A-Za-z0-9_-]/g,"_").slice(0,100)}.${e}`),Nt=(t,n)=>q(t,n,"json"),Y=(t,n)=>q(t,n,"notices");function X(t,n,e){let o=Y(t,n);z(S(o,".."),{recursive:!0}),bt(o,`${JSON.stringify(e)}
4
+ `)}function jt(t,n){let e=Y(t,n),o;try{o=V(e,"utf8")}catch{return[]}return Ot(e,{force:!0}),o.split(`
5
+ `).filter(Boolean).flatMap(r=>{try{return[String(JSON.parse(r))]}catch{return[]}})}function Dt(t){try{let n=JSON.parse(V(t,"utf8"));return n.version===1?n:null}catch{return null}}function G(t,n){z(S(t,".."),{recursive:!0});let e=`${t}.${process.pid}.tmp`;It(e,`${JSON.stringify(n,null,2)}
6
+ `),Tt(e,t)}var Z=t=>t==="~"||t.startsWith("~/")?S(Rt(),t.slice(1)):t;function Bt(t,n){let e;try{e=_t(Z(t),"r")}catch{return{ok:!1,offset:n,checkpoint:null}}try{let o=Ct(e).size,r=o<n?0:n,i=Buffer.alloc(o-r),c=i.length>0?Et(e,i,0,i.length,r):0,a=i.subarray(0,c).lastIndexOf(10);if(a<0)return{ok:!0,offset:r,checkpoint:null};let s=!0,l=null;for(let f of i.subarray(0,a).toString("utf8").split(`
7
+ `))if(f.trim())try{let u=JSON.parse(f);typeof u.step_index!="number"||typeof u.type!="string"?s=!1:u.type==="CHECKPOINT"&&(l=Math.max(l??-1,u.step_index))}catch{s=!1}return{ok:s,offset:r+a+1,checkpoint:l}}catch{return{ok:!1,offset:n,checkpoint:null}}finally{$t(e)}}function Kt(t){if(!t)return 0;try{return At(Z(t)).size}catch{return 0}}var Q=t=>{if(t.event.kind!=="prompt")return null;let n=jt(t.codeRoot,t.event.conversation),o=[Ft(t)?.context,...n].filter(Boolean).join(`
8
+
9
+ `);return o?{context:o}:null},Ft=({event:t,codeRoot:n,cache:e,host:o})=>{if(t.kind!=="prompt")return null;let r=Nt(n,t.conversation),i=_(e,o),c=Object.fromEntries(i.map(p=>[p.key,p.fingerprint])),a=Dt(r);if(!a)return G(r,{version:1,startedAt:new Date().toISOString(),reported:c,transcript:{offset:Kt(t.transcript),checkpoint:null}}),{context:v(n,e,o,!1)};let s=t.transcript?Bt(t.transcript,a.transcript.offset):{ok:!1,offset:a.transcript.offset,checkpoint:null},l=s.checkpoint!==null&&(a.transcript.checkpoint===null||s.checkpoint>a.transcript.checkpoint),f={...a,transcript:{offset:s.offset,checkpoint:l?s.checkpoint:a.transcript.checkpoint}},u=null;if(l)u=v(n,e,o,!0),f.reported=c;else if(t.newMessage){let p=i.filter(g=>a.reported[g.key]!==g.fingerprint).map(g=>`- ${g.text}`);if(!s.ok&&e.activeUnit){let g=`- Active unit: ${e.activeUnit}. If its requirements and test cases are no longer in view, call the BuildKeel get_context tool.`,H=p.findIndex(ut=>ut.startsWith("- Active unit:"));H>=0?p[H]=`${p[H]} If its requirements and test cases are no longer in view, call the BuildKeel get_context tool.`:p.unshift(g)}p.length>0&&(u=["BuildKeel:",...p].join(`
10
+ `)),f.reported=c}return JSON.stringify(f)!==JSON.stringify(a)&&G(r,f),u?{context:u}:null};import{appendFileSync as qt,mkdirSync as Yt}from"node:fs";import{dirname as Xt,join as Zt,resolve as Qt}from"node:path";import{existsSync as Pt,realpathSync as tt}from"node:fs";import{basename as Ut,dirname as et,isAbsolute as Lt,join as Jt,relative as ot,resolve as Mt,sep as Wt}from"node:path";var Gt={versions:"the frozen copy",approvals:"an approval record",completions:"a completion record",repins:"a re-pin decision record"},zt={"test-plan":"TP",design:"DD"},Vt=process.platform==="win32",h=t=>Vt?t.toLowerCase():t;function m(t,n){let e=nt(t,n);if(e!==null)return e;try{let o=n;for(;!Pt(o)&&et(o)!==o;)o=et(o);let r=Jt(tt(o),ot(o,n));return nt(tt(t),r)}catch{return null}}var k=(t,n)=>m(t,n);function nt(t,n){let e=ot(t,n);return e===""||e.startsWith("..")||Lt(e)?null:e.split(Wt).join("/")}function x(t,n){let e=k(t.specRoot,n);if(e===null)return null;let o=e.split("/"),r=t.documents??zt,i=o.length>=4&&o[2]!==void 0&&Object.hasOwn(r,o[2])?r[o[2]]:void 0,c=i!==void 0,a=o[c?3:2],s=`${o[1]??""}${c?`-${i}`:""}`,l=c?5:4;if(a&&o.length===l&&t.lockedDirs.map(h).includes(h(a))){if(h(a)==="versions"){let p=/^v(0|[1-9][0-9]*)\.md$/.exec(Ut(e))?.[1],g=p?`${s} v${p}`:s;return`BuildKeel: ${e} is the frozen copy of ${g}, which is approved and cannot be changed. To change ${s}, call the BuildKeel save_draft tool with id ${s} and the whole changed file: that opens the next version as a draft, and the approved version stays in force until the new one is approved.`}let u=Gt[a.toLowerCase()]??"a record";return`BuildKeel: ${e} is ${u} of ${s}. BuildKeel writes these records once and they are never edited, by hand or by the agent.`+(h(a)==="approvals"?" To approve a new version, use the BuildKeel approve tool.":"")}if((t.lockedSources??[]).find(u=>h(e).startsWith(`${h(u)}/`))){let u=`${o[1]??""}${c?`-${i}`:""}`;return`BuildKeel: ${e} is a source kept with ${u} v0, frozen when version 0 was approved: sources stay exactly as they were read. To change what ${u} says, call the BuildKeel save_draft tool with id ${u} and the whole changed file: that opens its next version as a draft.`}return t.lockedFiles.some(u=>h(u)===h(e))?`BuildKeel: ${e} is the working file of ${s}, which is approved and has no new version open, so it is not edited directly. To change ${s}, call the BuildKeel save_draft tool with id ${s} and the whole changed file: that opens the next version as a draft, and the approved version stays in force until the new one is approved.`:null}var rt=({event:t,cache:n})=>{if(t.kind!=="before-edit"&&t.kind!=="after-edit")return null;let e=n.lockMode??"block";if(!(e==="block"?t.kind==="before-edit":e==="warn"&&t.kind==="after-edit"))return null;let r=t.files.map(i=>x(n,Mt(t.cwd,i))).filter(i=>i!==null);return r.length===0?null:t.kind==="before-edit"?{block:r[0]}:{context:r.map(i=>`BuildKeel: this tree's lock gate is set to warn, so the edit went ahead. ${i.replace(/^BuildKeel: /,"")} Validation and the status overview report the change. Tell the user, and undo it unless they asked for it.`).join(`
11
+
12
+ `)}};var E=(t,n)=>Zt(t,d,"journal",`${n}.jsonl`),it=({event:t,codeRoot:n,cache:e})=>{if(t.kind!=="after-edit"||!e.activeUnit)return null;let o=new Date().toISOString(),r=[];for(let c of t.files){let a=Qt(t.cwd,c);if(x(e,a)||k(e.specRoot,a)!==null)continue;let s=m(n,a);if(s===null||s===d||s.startsWith(`${d}/`))continue;let l={at:o,tool:t.tool,file:s};r.push(JSON.stringify(l))}if(r.length===0)return null;let i=E(n,e.activeUnit);return Yt(Xt(i),{recursive:!0}),qt(i,`${r.join(`
13
+ `)}
14
+ `),null};import{resolve as te}from"node:path";var st=({event:t,codeRoot:n,cache:e,host:o})=>{if(t.kind!=="before-edit"||e.activeUnit||e.untrackedSince)return null;let r=t.files.flatMap(i=>{let c=te(t.cwd,i);if(k(e.specRoot,c)!==null)return[];let a=m(n,c);return a===null||a===d||a.startsWith(`${d}/`)?[]:[a]});return r.length===0?null:{block:`BuildKeel: there is no active unit in this working tree, so a change to ${r.join(", ")} would belong to no unit of work. Before changing it, ask the user how to go on, recommending the choice that fits: capture what you discussed with ${y(o,"capture")}, which turns it into the artifacts the team's process needs, to approve and then build; start the unit it belongs to with ${y(o,"start")} <ID>; record it as an ad-hoc unit, with a short title you propose (create it with the BuildKeel save_draft tool, type adhoc, then start it with start_work); or go ahead without a unit, which only the user can choose (then call the BuildKeel manage tool with action untracked). Make the change once one of these is done.`}};import{readFileSync as ee}from"node:fs";import{resolve as ne}from"node:path";function T(t,n){return n.some(e=>e.endsWith("/")?t.startsWith(e):t===e||t.startsWith(`${e}/`))}function O(t){let n=t.split("/"),e=n.at(-1)??"";return n.slice(0,-1).some(o=>["test","tests","__tests__","spec"].includes(o))||/[._-](test|spec)\.[^.]+$/.test(e)||/^test_.*\.py$/.test(e)}var A=8;function oe(t,n){try{let e=ee(E(t,n),"utf8").split(`
15
+ `).filter(Boolean);return new Set(e.map(o=>JSON.parse(o).file))}catch{return new Set}}var at=({event:t,codeRoot:n,cache:e})=>{if(t.kind!=="after-edit"||!e.activeUnit||e.scope.length===0)return null;let o=oe(n,e.activeUnit),r=[];for(let a of t.files){let s=ne(t.cwd,a);if(x(e,s)||k(e.specRoot,s)!==null)continue;let l=m(n,s);l===null||l===d||l.startsWith(`${d}/`)||!T(l,e.scope)&&!O(l)&&!o.has(l)&&!r.includes(l)&&r.push(l)}if(r.length===0)return null;let i=e.activeUnit,c=e.scope.slice(0,A).join(", ")+(e.scope.length>A?`, and ${e.scope.length-A} more`:"");return{context:`BuildKeel: ${r.join(", ")} ${r.length===1?"is":"are"} outside the areas ${i} relates to so far (${c}): its scope and its story's, and what its own work and the other work on its story changed. If the change belongs to ${i}, carry on and tell the user it widens what ${i} touches. If it belongs to other work, stop and ask the user which unit it belongs to.`}};function ct(t,n,e="claude-code"){if(t.kind==="ignored")return{};let o=w(t.cwd);if(!o)return{};let r=M(o);if(!r)return{};let i=n.map(s=>s({event:t,codeRoot:o,cache:r,host:e})).filter(s=>s!==null),c=i.find(s=>s.block)?.block,a=i.map(s=>s.context).filter(Boolean).join(`
16
+
17
+ `);return a&&t.kind==="after-edit"&&t.deferTo?(X(o,t.deferTo,a),c?{block:c}:{}):{...c?{block:c}:{},...a?{context:a}:{}}}var lt=[rt,st,at,it,W,Q];var se={"claude-code":U,antigravity:F};function ae(t){let n=t.indexOf("--host"),e=n>=0?t[n+1]:void 0,o=e&&I(e)?se[e]:void 0;if(!o)return process.stderr.write(`BuildKeel hook: unsupported host "${e??""}".
18
+ `),1;let r=t.filter((i,c)=>c!==n&&c!==n+1);try{let i=ie(0,"utf8");process.env.BUILDKEEL_HOOK_LOG&&re(process.env.BUILDKEEL_HOOK_LOG,`${JSON.stringify({host:e,args:r,input:i.trim()?JSON.parse(i):null})}
19
+ `);let c=o.parse(i.trim()?JSON.parse(i):{},r),a=ct(c,lt,e),{stdout:s,exitCode:l}=o.render(a,c);return s&&process.stdout.write(s),l}catch(i){process.stderr.write(`BuildKeel hook failed: ${i instanceof Error?i.message:String(i)}
20
+ `);let{stdout:c,exitCode:a}=o.failed(r);return c&&process.stdout.write(c),a}}process.exitCode=ae(process.argv.slice(2));