chamba 0.6.1 → 0.8.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.
- package/LICENSE +53 -14
- package/README.md +38 -11
- package/dist/commands/advanced.js +7 -278
- package/dist/commands/dev.js +11 -612
- package/dist/commands/doctor.js +1 -29
- package/dist/commands/menu.js +1 -80
- package/dist/commands/onboard.js +6 -230
- package/dist/commands/settings.js +15 -349
- package/dist/lib/agent-commands.js +2 -0
- package/dist/lib/agent-context.js +6 -184
- package/dist/lib/browser.js +1 -40
- package/dist/lib/chamba-yaml.js +10 -191
- package/dist/lib/constants.js +1 -125
- package/dist/lib/dockerfile-builder.js +41 -260
- package/dist/lib/env.js +2 -78
- package/dist/lib/git-env.js +1 -21
- package/dist/lib/global-config.js +4 -66
- package/dist/lib/pnpm-store.js +1 -19
- package/dist/lib/ports.js +1 -210
- package/dist/lib/safe-rm.js +1 -26
- package/dist/lib/sessions.js +2 -34
- package/dist/lib/shadows.js +1 -176
- package/dist/lib/skills.js +2 -0
- package/dist/lib/templates.js +1 -0
- package/dist/lib/webterm.js +1 -305
- package/dist/lib/workspace-identity.js +4 -260
- package/package.json +6 -6
- package/templates/Dockerfile +24 -12
- package/templates/claude-statusline.sh +5 -7
- package/templates/context/baseline.md +2 -0
- package/templates/pane-apps/client/assets/c-BNa-DeUl.json +3552 -0
- package/templates/pane-apps/client/assets/cpp-B-T4NRoH.json +20239 -0
- package/templates/pane-apps/client/assets/csharp-BbxHChhA.json +6010 -0
- package/templates/pane-apps/client/assets/css-CWCxuwmz.json +1860 -0
- package/templates/pane-apps/client/assets/diff-B-2N89g8.json +154 -0
- package/templates/pane-apps/client/assets/docker-DWTvYW26.json +103 -0
- package/templates/pane-apps/client/assets/files-D0nJgFAA.js +12 -0
- package/templates/pane-apps/client/assets/files-h0K1vZyQ.css +1 -0
- package/templates/pane-apps/client/assets/go-B2hyYeNg.json +3156 -0
- package/templates/pane-apps/client/assets/graphql-Z6Id2aNO.json +1292 -0
- package/templates/pane-apps/client/assets/html-BtzvlIfu.json +2627 -0
- package/templates/pane-apps/client/assets/ini-Bn3Twap1.json +108 -0
- package/templates/pane-apps/client/assets/java-C7t2dwLO.json +1885 -0
- package/templates/pane-apps/client/assets/javascript-DuC2v0C0.json +5996 -0
- package/templates/pane-apps/client/assets/json-CwdkWeV5.json +206 -0
- package/templates/pane-apps/client/assets/jsonc-MYWDbTU3.json +206 -0
- package/templates/pane-apps/client/assets/jsx-Cn8EZuIC.json +5996 -0
- package/templates/pane-apps/client/assets/kotlin-CFNOz1gw.json +580 -0
- package/templates/pane-apps/client/assets/make-BVnlFCcl.json +629 -0
- package/templates/pane-apps/client/assets/markdown-B4Xk2WM_.json +3263 -0
- package/templates/pane-apps/client/assets/php-CAQzQmmI.json +4188 -0
- package/templates/pane-apps/client/assets/python-CYQee8m4.json +4174 -0
- package/templates/pane-apps/client/assets/reviews-BsoGZ35r.css +1 -0
- package/templates/pane-apps/client/assets/reviews-iW0Mbn4e.js +153 -0
- package/templates/pane-apps/client/assets/ruby-D7R58tus.json +3114 -0
- package/templates/pane-apps/client/assets/rust-BFBbFiei.json +1103 -0
- package/templates/pane-apps/client/assets/scss-TQRhBkPG.json +1874 -0
- package/templates/pane-apps/client/assets/shellscript-DieAkC4W.json +2375 -0
- package/templates/pane-apps/client/assets/specs-D9z3neR-.js +13 -0
- package/templates/pane-apps/client/assets/sql-Bxd030LV.json +634 -0
- package/templates/pane-apps/client/assets/toml-ChrKGzsV.json +430 -0
- package/templates/pane-apps/client/assets/tsx-D2e90MFw.json +5996 -0
- package/templates/pane-apps/client/assets/typescript-DonXQ_n1.json +5747 -0
- package/templates/pane-apps/client/assets/xml-B17r2RXF.json +382 -0
- package/templates/pane-apps/client/assets/yaml-CKn4h1zy.json +627 -0
- package/templates/pane-apps/client/reviews/index.html +15 -0
- package/templates/pane-apps/client/specs/index.html +14 -0
- package/templates/pane-apps/server/reviews.mjs +20 -0
- package/templates/pane-apps/server/specs.mjs +5 -0
- package/templates/skills/chamba-statusline/SKILL.md +7 -19
- package/templates/skills/dx-review/SKILL.md +123 -0
- package/templates/skills/dx-review/references/acts.md +162 -0
- package/templates/skills/dx-spec/SKILL.md +561 -0
- package/templates/skills/dx-spec/references/imagination-guide.md +140 -0
- package/templates/skills/dx-spec/references/principles-template.md +2 -0
- package/templates/skills/dx-spec/references/review-guide.md +127 -0
- package/templates/skills/dx-spec/references/spec-guide.md +145 -0
- package/templates/skills/dx-spec/references/stages.md +484 -0
- package/templates/skills/dx-spec-execute/SKILL.md +437 -0
- package/templates/startup.mjs +10 -4
- package/templates/tool-helper.sh +166 -0
- package/templates/webterm/README.md +79 -9
- package/templates/webterm/color.js +61 -0
- package/templates/webterm/config.js +74 -0
- package/templates/webterm/context/claude.md +0 -1
- package/templates/webterm/public/app/alerts.js +4 -4
- package/templates/webterm/public/app/anchored.js +81 -0
- package/templates/webterm/public/app/composer.js +4 -1
- package/templates/webterm/public/app/connection.js +9 -0
- package/templates/webterm/public/app/dom.js +15 -5
- package/templates/webterm/public/app/frames.js +51 -10
- package/templates/webterm/public/app/main.js +26 -6
- package/templates/webterm/public/app/new-session.js +13 -41
- package/templates/webterm/public/app/palette.js +58 -0
- package/templates/webterm/public/app/pane-shape.js +167 -0
- package/templates/webterm/public/app/pane-shell.js +380 -0
- package/templates/webterm/public/app/pane.js +77 -193
- package/templates/webterm/public/app/reviews-host.js +15 -0
- package/templates/webterm/public/app/specs-host.js +16 -0
- package/templates/webterm/public/app/state.js +5 -0
- package/templates/webterm/public/app/tabs.js +6 -2
- package/templates/webterm/public/app/terminal.js +8 -0
- package/templates/webterm/public/app/theme.js +75 -27
- package/templates/webterm/public/app/tool-host.js +302 -0
- package/templates/webterm/public/app/workspace-color.js +192 -0
- package/templates/webterm/public/index.html +68 -30
- package/templates/webterm/public/styles.css +270 -34
- package/templates/webterm/server.js +321 -0
- package/templates/webterm/tool-document.js +67 -0
- package/templates/webterm/tools/commands.js +61 -0
- package/templates/webterm/tools/index.js +25 -0
- package/templates/webterm/tools/mount.js +337 -0
- package/templates/webterm/tools/paths.js +34 -0
- package/templates/webterm/tools/reviews.js +133 -0
- package/templates/webterm/tools/specs.js +154 -0
- package/templates/webterm/typed-line.js +148 -0
- package/templates/context/context-usage.md +0 -1
- package/templates/context-usage.sh +0 -266
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import{closeSync as e,constants as t,existsSync as n,fstatSync as r,lstatSync as i,mkdirSync as a,openSync as o,readFileSync as s,readdirSync as c,readlinkSync as l,realpathSync as u,renameSync as d,rmSync as f,statSync as p,watch as m,writeFileSync as h}from"node:fs";import{basename as g,dirname as _,isAbsolute as v,join as y,relative as ee,resolve as b,sep as x}from"node:path";import{createHash as S}from"node:crypto";import{execFile as te}from"node:child_process";function ne(e){return e.toLowerCase().replace(/`/g,``).replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``)||``}var C=`.reviews`,w=`archive`,re=`state.json`,ie=`marks.json`,ae=`threads.json`,oe=`pending.json`,se=`dismissals.json`,ce=`reader-state.json`,le=`approval.json`,ue=`signature.png`,de=`sends`,T=`baseline`,fe=`baseline.next`,pe=`baseline.gone`,me=`baseline.json`,he=`diff.patch`,ge=`blobs`,_e=`metadata.json`;function ve(e){let t=e.indexOf(`/${C}/`);return!(t===-1||e.slice(t+8+2)===`reader-state.json`)}var ye=[`# Written by the Code Reviews tool when this root was created.`,`# Git keeps the record of a review. What is named here is a snapshot of the`,`# code, the agent labels on it, or one reader place, and none of it is history.`,`*/${C}/${fe}/`,`*/${C}/${pe}/`,`*/${C}/${T}/${he}`,`*/${C}/${T}/${ge}/`,`*/${C}/${T}/${_e}`,`*/${C}/${oe}`,`*/${C}/${ce}`,`${w}/*/${C}/${fe}/`,`${w}/*/${C}/${pe}/`,`${w}/*/${C}/${T}/${he}`,`${w}/*/${C}/${T}/${ge}/`,`${w}/*/${C}/${T}/${_e}`,`${w}/*/${C}/${oe}`,`${w}/*/${C}/${ce}`],be=12;function xe(e){let t=e=>e.slice(0,be);if(e.followed!==null)return`commit ${t(e.followed)}`;if(e.kind===`branch`||e.kind===`other-branch`){let n=e.baseRef??t(e.base),r=`${e.head} against ${n}`;return e.uncommitted?`${r} - includes uncommitted changes`:r}return e.kind===`range`?`${t(e.base)}..${t(e.head)}`:e.kind===`last-commit`?`last commit ${t(e.head)}`:`commit ${t(e.head)}`}function Se(e){let t=new Date(e);if(!/^\d{4}-\d{2}-\d{2}/.test(e)||Number.isNaN(t.getTime()))return``;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())}`}function Ce(e){let t=e.state,n=[`# ${t.name||t.slug||`A review`}`,``],r=Se(t.created);if(r&&n.push(`- Filed: ${r} from the ${t.filedBy}`),n.push(`- Status: ${t.status}`),n.push(`- Reviewing: ${xe(t.selection)}`),n.push(`- Seen: ${e.seen} of ${e.total} hunks`),n.push(`- Feedback loops: ${e.loops}`),e.threads.total>0&&n.push(`- Threads: ${e.threads.total}, ${e.threads.open} open`),t.side===`agent`&&n.push(`- Awaits the agent: ${t.agent.activity||t.agent.act||`working`}`),e.commit&&n.push(`- Commit: ${e.commit}`),e.fingerprint&&n.push(`- Fingerprint: ${e.fingerprint}`),e.metadata.groups.length>0){n.push(``,`## Groups`,``);for(let t of e.metadata.groups){n.push(`### ${t.name||t.id}`,``),t.narrative&&n.push(t.narrative,``);for(let e of t.facts)n.push(`- ${e}`);t.facts.length>0&&n.push(``),n.push(`${t.hunks.length} ${t.hunks.length===1?`hunk`:`hunks`}`,``)}for(;n[n.length-1]===``;)n.pop()}let i=e.approval;if(i!==null){n.push(``,`## The ending`,``);let e=Se(i.at);if(i.approved){let t=i.name||`the reviewer`;n.push(`Approved by ${t}${e?` on ${e}`:``}.`),i.signature&&n.push(``,`Signed by hand.`)}else n.push(`Closed without approval${e?` on ${e}`:``}.`),i.reason&&n.push(``,i.reason);i.uncommitted&&n.push(``,`Uncommitted changes were part of what was reviewed.`)}if(t.log.length>0){n.push(``,`## Log`,``);for(let e of t.log){let t=Se(e.at);n.push(t?`- ${t}: ${e.said}`:`- ${e.said}`)}}return`${n.join(`
|
|
2
|
+
`)}\n`}function we(e){return e.messages.filter(e=>e.from===`agent`&&e.readAt===null).length}var Te=[`undo`,`explain`,`comment`,`group-comment`,`fix`],Ee={undo:`Undo the change`,explain:`Explain in a comment`,comment:`Comment`,"group-comment":`Comment on group`,fix:`Fix`};function De(e){return e!==`undo`}function Oe(e){if(e.length===0)return``;let t=[...e].sort((e,t)=>e-t),n=t[0],r=t[t.length-1];return n===void 0||r===void 0?``:n===r?`L${n}`:`L${n}-L${r}`}var ke=[`info`,`attention`,`issue`];function Ae(e,t,n){let r=`${e}\n${(t??[]).join(`,`)}\n${n}`,i=3735928559,a=1103547991;for(let e=0;e<r.length;e+=1){let t=r.charCodeAt(e);i=Math.imul(i^t,2654435761),a=Math.imul(a^t,1597334677)}return i=Math.imul(i^i>>>16,2246822507)^Math.imul(a^a>>>13,3266489909),a=Math.imul(a^a>>>16,2246822507)^Math.imul(i^i>>>13,3266489909),(a>>>0).toString(16).padStart(8,`0`)+(i>>>0).toString(16).padStart(8,`0`)}function je(e,t){return`${e}\n${t}`}var Me=`ungrouped`,E=e=>typeof e==`object`&&!!e&&!Array.isArray(e),D=(e,t=``)=>typeof e==`string`?e:t,O=e=>typeof e==`string`?e:null,k=(e,t=0)=>typeof e==`number`&&Number.isFinite(e)?e:t,A=e=>Array.isArray(e)?e:[],Ne=e=>A(e).filter(e=>typeof e==`string`);function j(e){if(e==null||e.trim()===``)return null;try{let t=JSON.parse(e);return E(t)?t:null}catch{return null}}function Pe(e=``){return{version:1,fingerprint:e,marks:[],acts:[],changed:[]}}function Fe(e){let t=j(e);if(t===null)return Pe();let n=[`hunk`,`file`,`group`,`unseen`];return{version:k(t.version,1),fingerprint:D(t.fingerprint),marks:A(t.marks).filter(E).map(e=>({hunk:D(e.hunk),at:D(e.at),act:D(e.act),content:D(e.content)})).filter(e=>e.hunk!==``),acts:A(t.acts).filter(E).map(e=>{let t=D(e.kind);return{id:D(e.id),at:D(e.at),kind:n.includes(t)?t:`hunk`,container:O(e.container),hunks:Ne(e.hunks)}}).filter(e=>e.id!==``),changed:A(t.changed).filter(E).map(e=>({hunk:D(e.hunk),at:D(e.at),content:D(e.content)})).filter(e=>e.hunk!==``)}}function Ie(e=``){return{version:1,fingerprint:e,threads:[]}}function Le(e){let t=j(e);if(t===null)return Ie();let n=[`you`,`agent`,`tool`];return{version:k(t.version,1),fingerprint:D(t.fingerprint),threads:A(t.threads).filter(E).map(e=>({id:D(e.id),kind:e.kind===`group`?`group`:`hunk`,anchor:D(e.anchor),open:e.open!==!1,label:e.label===`hunk-removed`?`hunk-removed`:null,closedAt:O(e.closedAt),messages:A(e.messages).filter(E).map(e=>{let t=D(e.from);return{id:D(e.id),from:n.includes(t)?t:`tool`,at:D(e.at),text:D(e.text),readAt:O(e.readAt)}}).filter(e=>e.id!==``)})).filter(e=>e.id!==``&&e.anchor!==``)}}function Re(e=``){return{version:1,fingerprint:e,items:[]}}function ze(e){let t=j(e);return t===null?Re():{version:k(t.version,1),fingerprint:D(t.fingerprint),items:A(t.items).filter(E).map(e=>{let t=D(e.act);return{id:D(e.id),at:D(e.at),act:Te.includes(t)?t:`comment`,hunk:O(e.hunk),group:O(e.group),lines:Ve(e.lines),text:D(e.text),label:e.label===`hunk-removed`?`hunk-removed`:null}}).filter(e=>e.id!==``&&(e.hunk!==null||e.group!==null))}}function Be(e){let t=j(e);return t===null?null:{version:k(t.version,1),sentAt:D(t.sentAt),fingerprint:D(t.fingerprint),items:A(t.items).filter(E).map(e=>{let t=D(e.act);return{hunk:O(e.hunk),act:Te.includes(t)?t:`comment`,group:O(e.group),lines:Ve(e.lines),text:D(e.text)}})}}function Ve(e){if(!Array.isArray(e))return null;let t=e.filter(e=>Number.isInteger(e)&&e>0);return t.length===0?null:t}function He(e=``){return{version:1,fingerprint:e,items:[]}}function Ue(e){let t=j(e);return t===null?He():{version:k(t.version,1),fingerprint:D(t.fingerprint),items:A(t.items).filter(E).map(e=>({hunk:D(e.hunk),key:D(e.key),at:D(e.at)})).filter(e=>e.hunk!==``&&e.key!==``)}}function We(e=``){return{version:1,fingerprint:e,groups:[],notes:[]}}function Ge(e){let t=j(e);return t===null?We():{version:k(t.version,1),fingerprint:D(t.fingerprint),groups:A(t.groups).filter(E).map(e=>({id:D(e.id),name:D(e.name),narrative:D(e.narrative),facts:Ne(e.facts),hunks:Ne(e.hunks)})).filter(e=>e.id!==``),notes:A(t.notes).filter(E).map(e=>({hunk:D(e.hunk),kind:D(e.kind),lines:Array.isArray(e.lines)?e.lines.filter(e=>typeof e==`number`):null,text:D(e.text),key:D(e.key)})).filter(e=>e.hunk!==``&&e.key!==``&&ke.includes(e.kind))}}function Ke(){return{version:1,scroll:0,expanded:[],group:null,drafts:[],at:``}}function qe(e){let t=j(e);return t===null?Ke():{version:k(t.version,1),scroll:k(t.scroll),expanded:Ne(t.expanded),group:O(t.group),drafts:Je(t.drafts),at:D(t.at)}}function Je(e){let t=[];for(let n of A(e)){if(!E(n))continue;let e=D(n.anchor),r=D(n.act);e===``||!(r in Ee)||t.push({anchor:e,act:r,lines:A(n.lines).filter(e=>typeof e==`number`&&Number.isInteger(e)&&e>0),text:D(n.text)})}return t}function Ye(e){let t=j(e);return t===null?null:{version:k(t.version,1),approved:t.approved===!0,at:D(t.at),name:D(t.name),signature:O(t.signature),reason:D(t.reason),loops:k(t.loops),fingerprint:D(t.fingerprint),commit:D(t.commit),uncommitted:t.uncommitted===!0}}var Xe=600*1e3;function Ze(e,t){if(e===null)return!1;let n=new Date(e).getTime();return!Number.isNaN(n)&&t.getTime()-n>Xe}var Qe=[`reviewing`,`approved`,`closed`,`archived`],$e=[`prepare`,`process`,`sync`],et=e=>typeof e==`object`&&!!e&&!Array.isArray(e),M=(e,t=``)=>typeof e==`string`?e:t,tt=e=>typeof e==`string`?e:null,nt=e=>typeof e==`number`&&Number.isInteger(e)&&e>=0?e:null;function rt(e,t,n,r,i){return{version:1,name:e,slug:t,selection:n,status:`reviewing`,side:`agent`,agent:{act:`prepare`,activity:`Preparing the review`,groups:null,lastPostAt:i},filedBy:r,created:i,log:[{at:i,said:`filed from the ${r===`form`?`form`:`terminal`}`}]}}function it(e,t){if(e==null||e.trim()===``)return null;let n;try{n=JSON.parse(e)}catch{return null}if(!et(n))return null;let r=et(n.selection)?n.selection:null;if(r===null)return null;let i=et(n.agent)?n.agent:{},a=M(n.status),o=M(i.act);return{version:typeof n.version==`number`?n.version:1,name:M(n.name,t),slug:M(n.slug,t),selection:r,status:Qe.includes(a)?a:`reviewing`,side:n.side===`agent`?`agent`:`you`,agent:{act:$e.includes(o)?o:null,activity:M(i.activity),groups:nt(i.groups),lastPostAt:tt(i.lastPostAt)},filedBy:n.filedBy===`terminal`?`terminal`:`form`,created:M(n.created),log:Array.isArray(n.log)?n.log.filter(et).map(e=>({at:M(e.at),said:M(e.said)})).filter(e=>e.said!==``):[]}}function at(e){let t=e?.code;return typeof t==`string`&&ot.has(t)?t:null}var ot=new Set([`path-refused`,`no-entry`,`no-file`,`bad-request`,`too-large`,`upstream-failed`,`unreadable-answer`]),N=class extends Error{requested;code=`path-refused`;constructor(e,t){super(`${e}: refused path ${t}`),this.requested=t,this.name=`PathRefused`}},st=class extends Error{requested;code=`no-entry`;constructor(e,t){super(`${e}: no directory at ${t}`),this.requested=t,this.name=`NoSuchEntry`}},ct=class extends Error{requested;code=`no-file`;constructor(e,t,n=`not a file`){super(`${e}: ${n} - ${t}`),this.requested=t,this.name=`NoSuchFile`}},lt=class extends Error{requested;size;code=`too-large`;constructor(e,t,n){super(`${e}: too large to serve - ${t}`),this.requested=t,this.size=n,this.name=`FileTooLarge`}};function ut(e){switch(at(e)){case`path-refused`:return 403;case`no-entry`:case`no-file`:return 404;case`bad-request`:return 400;case`too-large`:return 413;case`upstream-failed`:case`unreadable-answer`:return 502}return dt(e)?404:500}function dt(e){let t=e?.code;return t===`ENOENT`||t===`ENOTDIR`}var ft=32*1024*1024;new Set(`txt text log json yaml yml toml ini cfg conf csv tsv xml css scss js jsx mjs cjs ts tsx py rb go rs java kt swift c h cpp hpp sh bash zsh fish sql graphql gql env diff patch lock gitignore editorconfig`.split(` `));function pt(e){let t=e.slice(e.lastIndexOf(`/`)+1).slice(1).match(/\.([^.]+)$/);return t?t[1].toLowerCase():``}function mt(e){return e.startsWith(`.`)}function ht(e){let t=e,n=[];for(;;)try{return y(u(t),...n)}catch{let r=_(t);if(r===t)return e;n.unshift(g(t)),t=r}}function gt(e){return ht(b(e))}function _t(e){return e.split(`/`).some(e=>e!==``&&mt(e))}function vt(e,t,n,r){let i=n.replace(/^\/+/,``);if(v(n)||i.includes(`\0`))throw new N(e,n);let a=r===`require`;if(_t(i)!==a)throw new N(e,n);let o=b(t,i);if(!xt(t,o)||!xt(t,ht(o))||_t(ee(t,o).split(x).join(`/`))!==a)throw new N(e,n);return o}function yt(e,t,n){return vt(e,t,n,`refuse`)}function bt(e,t,n){return vt(e,t,n,`require`)}function xt(e,t){return t===e||t.startsWith(e+x)}function St(e,t=`children`){if(t===`self`)return``;let n=e.split(`/`).filter(Boolean);return n.length<2?``:n[0]===`archive`?n.length>2?`archive/${n[1]}`:``:n[0]}var Ct={md:`text/markdown; charset=utf-8`,markdown:`text/markdown; charset=utf-8`,html:`text/html; charset=utf-8`,htm:`text/html; charset=utf-8`,css:`text/css; charset=utf-8`,js:`text/javascript; charset=utf-8`,json:`application/json; charset=utf-8`,svg:`image/svg+xml`,png:`image/png`,jpg:`image/jpeg`,jpeg:`image/jpeg`,gif:`image/gif`,webp:`image/webp`,avif:`image/avif`,bmp:`image/bmp`,ico:`image/x-icon`,pdf:`application/pdf`,txt:`text/plain; charset=utf-8`};function wt(e){return Ct[pt(e)]??`application/octet-stream`}var Tt=ft;function Et(e,t,n){return Ot(e,yt(e,t,n),n)}function Dt(e,t,n,r){let i=n.replace(/^\/+/,``);if(!r(i))throw new N(e,n);return Ot(e,bt(e,t,i),n)}function Ot(n,i,a){let c=o(i,t.O_RDONLY|t.O_NOFOLLOW);try{let e=r(c);if(!e.isFile())throw new ct(n,a);if(e.size>Tt)throw new lt(n,a,e.size);return{bytes:s(c),mediaType:wt(a),size:e.size,modified:new Date(e.mtimeMs).toISOString()}}finally{e(c)}}var kt=`.tmp-`;function At(e){return e.slice(e.lastIndexOf(`/`)+1).includes(kt)}function P(e,t){a(_(e),{recursive:!0});let n=`${e}${kt}${process.pid}-${Math.random().toString(36).slice(2)}`;try{h(n,t),d(n,e)}finally{f(n,{force:!0})}}function jt(e,t,n,r){P(bt(e,t,n),r)}function Mt(e,t,n){let r=bt(e,t,n);try{return s(r,`utf8`)}catch{return null}}function Nt(e){try{let t=i(e);return{directory:t.isDirectory(),id:t.ino}}catch{return{directory:!1,id:0}}}function Pt(e,t,r={}){let i=r.entries??`children`,a=r.coalesce??`per-path`,o=r.debounceMs??120,s=r.shared??(()=>!1),l=new Map,u=null,d=new Map,f=!1,p=t=>t===``?e:`${e}/${t}`,h=()=>{u=null;let e=[...l.values()];l.clear();for(let n of e)try{t(n)}catch{}},g=e=>{if(e===``||At(e)||_t(e)&&!s(e))return;let t=St(e,i);if(a===`per-entry`)l.set(t,{entry:t,path:t,kind:`changed`});else{let r=n(p(e))?`changed`:`gone`;l.set(e,{entry:t,path:e,kind:r})}u||=setTimeout(h,o)},_=e=>{for(let[t,n]of d)(t===e||t.startsWith(`${e}/`))&&(n.watcher.close(),d.delete(t))},v=e=>{if(f||d.has(e))return;let t;try{t=m(p(e),(t,r)=>{if(!r)return;let i=r.toString();if(i===``)return;let a=e===``?i:`${e}/${i}`;if(i===e.split(`/`).at(-1)&&!n(p(a)))return;let o=d.get(a),s=Nt(p(a));if(o&&s.directory){if(o.id===s.id)return;_(a),v(a),g(a);return}g(a),o?_(a):s.directory&&v(a)})}catch{return}t.on(`error`,()=>_(e)),d.set(e,{watcher:t,id:Nt(p(e)).id});for(let t of y(e))v(t)},y=e=>{try{return c(p(e),{withFileTypes:!0}).filter(e=>e.isDirectory()).map(t=>e===``?t.name:`${e}/${t.name}`)}catch{return[]}};return v(``),{refollow(){f||v(``)},close(){f=!0,u&&clearTimeout(u),u=null;for(let e of d.values())e.watcher.close();d.clear()}}}var Ft={A:`added`,C:`copied`,D:`deleted`,M:`modified`,R:`renamed`,T:`type-changed`,U:`unmerged`,X:`unknown`},F=class extends Error{code=`unreadable-answer`;constructor(e){super(`reviews: ${e}`),this.name=`UnreadableDiff`}},It=new WeakMap;function Lt(e){return It.get(e)??null}function I(e){return Buffer.from(e,`latin1`).toString(`utf8`)}function L(e){let t=(Buffer.isBuffer(e)?e:Buffer.from(e,`utf8`)).toString(`latin1`);if(t.trim()===``)return{files:[]};let n=[],r=t;for(;r!==``;){let e=Rt(r);n.push(...e.files),r=e.rest}return{files:n}}function Rt(e){let{raw:t,patch:n,rest:r}=Bt(e),i=t.map(e=>({path:e.path,oldPath:e.oldPath,status:e.status,similarity:e.similarity,oldMode:e.oldMode,newMode:e.newMode,oldOid:e.oldOid,newOid:e.newOid,binary:!1,hunks:[]}));Ut(n,i,t);for(let e of i)e.path=I(e.path),e.oldPath=e.oldPath===null?null:I(e.oldPath);return{files:i,rest:r}}var zt=/^:\d{6} \d{6} [0-9a-f]+ [0-9a-f]+ [A-Z]\d*$/;function Bt(e){let t=[],n=t=>{let n=e.indexOf(`\0`,t);return n===-1?{value:e.slice(t),next:e.length}:{value:e.slice(t,n),next:n+1}},r=0;for(;;){let i=n(r);if(!i.value.startsWith(`:`))break;let a=Ht(i.value),o=a.status===`renamed`||a.status===`copied`?2:1,s=[],c=i.next;for(let t=0;t<o;t+=1){if(c>=e.length)throw new F(`a raw record names no path: ${i.value}`);let t=n(c);s.push(t.value),c=t.next}t.push(o===2?{...a,oldPath:s[0],path:s[1]}:{...a,oldPath:null,path:s[0]}),r=c}for(;e[r]===`\0`;)r+=1;let i=Vt(e,r);return{raw:t,patch:e.slice(r,i),rest:e.slice(i)}}function Vt(e,t){let n=t;for(;n<e.length;){let r=e.indexOf(`:`,n);if(r===-1)return e.length;if(r===t||e[r-1]===`
|
|
3
|
+
`){let t=e.indexOf(`\0`,r),n=t===-1?e.slice(r):e.slice(r,t);if(zt.test(n))return r}n=r+1}return e.length}function Ht(e){let t=e.slice(1).split(` `);if(t.length!==5)throw new F(`a raw record reads wrong: ${e}`);let[n,r,i,a,o]=t,s=Ft[o.slice(0,1)];if(!s)throw new F(`a raw record carries no status: ${e}`);let c=o.slice(1);return{oldMode:n,newMode:r,oldOid:i,newOid:a,status:s,similarity:c===``?null:Number(c)}}function Ut(e,t,n){if(e===``)return;let r=e.split(`
|
|
4
|
+
`);r.at(-1)===``&&r.pop();let i=0,a=-1;for(;i<r.length;){let e=r[i];if(!e.startsWith(`diff --git `))throw new F(`the patch does not start a file at line ${i+1}`);a+=1;let o=t[a],s=n[a];if(!o||!s)throw new F(`the patch holds more files than the raw record`);Wt(e,s),i=Kt(r,i+1,o)}if(a+1!==t.length)throw new F(`the raw record names ${t.length} files and the patch holds ${a+1}`)}function Wt(e,t){let n=t.oldPath??t.path,r=t.path,i=`diff --git a/${n} b/${r}`,a=`diff --git ${Gt(`a/${n}`)} ${Gt(`b/${r}`)}`;if(e!==i&&e!==a)throw new F(`the patch and the raw record disagree about ${r}`)}function Gt(e){let t={"\x07":`\\a`,"\b":`\\b`,"\f":`\\f`,"\n":`\\n`,"\r":`\\r`," ":`\\t`,"\v":`\\v`,'"':`\\"`,"\\":`\\\\`},n=``;for(let r of e){let e=t[r];if(e){n+=e;continue}let i=r.codePointAt(0)??0;n+=i<32||i===127?`\\${i.toString(8).padStart(3,`0`)}`:r}return`"${n}"`}function Kt(e,t,n){let r=t;for(;r<e.length;){let t=e[r];if(t.startsWith(`diff --git `))return r;if(t.startsWith(`@@`)){r=Jt(e,r,n);continue}(t.startsWith(`Binary files `)||t===`GIT binary patch`)&&(n.binary=!0),r+=1}return r}var qt=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(?: (.*))?$/;function Jt(e,t,n){let r=e[t],i=qt.exec(r);if(!i)throw new F(`a hunk header reads wrong: ${r}`);let a=Number(i[1]),o=i[2]===void 0?1:Number(i[2]),s=Number(i[3]),c=i[4]===void 0?1:Number(i[4]),l={header:I(r),heading:I(i[5]??``),oldStart:a,oldLines:o,newStart:s,newLines:c,lines:[]},u=[],d=a,f=s,p=0,m=0,h=t+1;for(;p<o||m<c;){if(h>=e.length)throw new F(`a hunk ends early: ${r}`);let t=e[h];if(h+=1,t.startsWith(`\\`)){let e=l.lines.at(-1);e&&(e.noNewline=!0);continue}let n=t.slice(0,1),i=t.slice(1);if(n===`+`){u.push(`+${i}`),l.lines.push({kind:`add`,text:I(i),oldLine:null,newLine:f,noNewline:!1}),f+=1,m+=1;continue}if(n===`-`){u.push(`-${i}`),l.lines.push({kind:`remove`,text:I(i),oldLine:d,newLine:null,noNewline:!1}),d+=1,p+=1;continue}if(n===` `||t===``){l.lines.push({kind:`context`,text:I(i),oldLine:d,newLine:f,noNewline:!1}),d+=1,f+=1,p+=1,m+=1;continue}throw new F(`a hunk holds a line that is not one: ${t.slice(0,40)}`)}if(It.set(l,u.join(`
|
|
5
|
+
`)),n.hunks.push(l),(e[h]??``).startsWith(`\\`)){let e=l.lines.at(-1);e&&(e.noNewline=!0),h+=1}return h}function Yt(e){let t=0,n=0;for(let r of e.hunks)for(let e of r.lines)e.kind===`add`&&(t+=1),e.kind===`remove`&&(n+=1);return{added:t,deleted:n}}var Xt=`/usr/bin/git`,Zt=3e4,Qt=64*1024*1024,$t=[`diff.algorithm=histogram`,`diff.context=3`,`diff.interHunkContext=0`,`diff.indentHeuristic=true`,`diff.renames=true`,`diff.renameLimit=1000`,`diff.relative=false`,`diff.srcPrefix=a/`,`diff.dstPrefix=b/`,`core.quotepath=false`,`diff.noprefix=false`,`diff.mnemonicPrefix=false`,`core.autocrlf=false`,`core.bigFileThreshold=512m`,`diff.suppressBlankEmpty=false`,`core.fsmonitor=false`,`core.hooksPath=/dev/null`],en={GIT_CONFIG_NOSYSTEM:`1`,GIT_CONFIG_GLOBAL:`/dev/null`,GIT_OPTIONAL_LOCKS:`0`,LC_ALL:`C`,PATH:`/usr/bin:/bin`},tn=[`--no-color`,`--no-ext-diff`,`--no-textconv`],nn=new Set([`diff-no-index`]),rn=class extends Error{operation;said;tooMuch;code=`upstream-failed`;constructor(e,t,n=!1){super(`reviews: git ${e} failed - ${t}`),this.operation=e,this.said=t,this.tooMuch=n,this.name=`GitFailed`}},R=class extends Error{code=`bad-request`;constructor(e){super(`reviews: ${e}`),this.name=`NotAllowed`}};function an(e){return/^[0-9a-f]{40}$|^[0-9a-f]{64}$/.test(e)}function on(e){if(!an(e))throw new R(`${e} is not a resolved commit`);return e}function z(e,t){if(t===``)throw new R(`${e} is empty`);if(t.startsWith(`-`))throw new R(`${e} is spelled as an option: ${t}`);if(/[\0\n\r]/.test(t))throw new R(`${e} holds a line break or a null byte`);return t}function sn(e,t){if(z(e,t),t.startsWith(`/`))throw new R(`${e} is absolute: ${t}`);if(t.split(`/`).includes(`..`))throw new R(`${e} climbs out of the workspace: ${t}`);return t}function cn(e,t){if(t===``)throw new R(`${e} is empty`);if(t.includes(`\0`))throw new R(`${e} holds a null byte`);if(t.startsWith(`/`))throw new R(`${e} is absolute: ${t}`);if(t.split(`/`).includes(`..`))throw new R(`${e} climbs out of the workspace: ${t}`);return t}function ln(e){return e.map(e=>`:(exclude,top)${sn(`an excluded root`,e).replace(/\/+$/,``)}/`)}function un(e,t){let n=b(t);return e.map(e=>{if(!v(e))return e;let t=ee(n,b(e));if(t===``||t.startsWith(`..`)||v(t))throw new R(`the excluded root ${e} is not inside ${n}`);return t.split(x).join(`/`)})}function dn(e){let t=ln(e),n=(e,t)=>e===null?[t]:[`${z(`a ref`,e)}..${t}`];return{"rev-parse":e=>[`rev-parse`,`--verify`,`--quiet`,`--end-of-options`,`${z(`a ref`,e)}^{commit}`],"rev-parse-abbrev":()=>[`rev-parse`,`--abbrev-ref`,`HEAD`],"rev-parse-git-dir":()=>[`rev-parse`,`--git-dir`],"rev-parse-top":()=>[`rev-parse`,`--show-toplevel`],"for-each-ref":()=>[`for-each-ref`,`--format=%(refname:short)%09%(objectname)%09%(upstream:short)`,`--`,`refs/heads/`],"reflog-show":e=>[`reflog`,`show`,`--format=%gd%x09%gs`,`--end-of-options`,z(`a ref`,e)],"reflog-head":()=>[`reflog`,`show`,`--format=%gd%x09%gs`,`--end-of-options`,`HEAD`],"merge-base":(e,t)=>[`merge-base`,`--end-of-options`,z(`a ref`,e),z(`a ref`,t)],"merge-base-ancestor":(e,t)=>[`merge-base`,`--is-ancestor`,`--end-of-options`,z(`a ref`,e),z(`a ref`,t)],log:(e,r)=>[`log`,`--format=%H%x09%P%x09%an%x09%aI%x09%s`,`--end-of-options`,...n(e,z(`a ref`,r)),`--`,...t],"log-first-parent":(e,t)=>[`log`,`--first-parent`,`--format=%H%x09%P%x09%an%x09%aI%x09%s`,`--end-of-options`,...n(e,z(`a ref`,t))],diff:(e,n,r,i=[])=>[`diff`,...tn,`--find-renames`,`--unified=3`,`--raw`,`--patch`,`-z`,`--no-abbrev`,`--end-of-options`,...fn(e,n,r),`--`,...t,...i.map(e=>`:(exclude,top)${cn(`an excluded path`,e)}`)],"diff-text":(e,t,n,r)=>[`diff`,...tn,`--find-renames`,`--text`,`--unified=3`,`--raw`,`--patch`,`-z`,`--no-abbrev`,`--end-of-options`,...fn(e,t,n),`--`,...pn(r).map(e=>`:(top,literal)${cn(`a path`,e)}`)],numstat:(e,n,r)=>[`diff`,...tn,`--find-renames`,`--numstat`,`-z`,`--end-of-options`,...fn(e,n,r),`--`,...t],"diff-no-index":e=>[`diff`,...tn,`--no-index`,`--unified=3`,`--raw`,`--patch`,`-z`,`--no-abbrev`,`--`,`/dev/null`,cn(`a path`,e)],"ls-files-others":()=>[`ls-files`,`--others`,`--exclude-standard`,`-z`,`--`,...t],"ls-files":()=>[`ls-files`,`-z`,`--`,...t],"diff-tree":e=>[`diff-tree`,...tn,`--no-commit-id`,`--numstat`,`-r`,`--find-renames`,`--end-of-options`,z(`a commit`,e),`--`,...t],show:e=>[`show`,...tn,`--no-patch`,`--format=%H%x09%P%x09%an%x09%aI%x09%s`,`--end-of-options`,z(`a commit`,e)],status:()=>[`status`,`--porcelain`,`-z`,`--`,...t],"check-attr":e=>[`check-attr`,`-z`,`linguist-generated`,`--`,...e.map(e=>cn(`a path`,e))],"cat-file-blob":e=>[`cat-file`,`blob`,`--end-of-options`,mn(e)],"cat-file-type":e=>[`cat-file`,`-t`,`--end-of-options`,mn(e)],"config-user-name":()=>[`config`,`--get`,`--end-of-options`,`user.name`]}}function fn(e,t,n){let r=z(`a ref`,e);if(n)return[r];if(t===null)throw new R(`a diff of committed code names both ends`);return[r,z(`a ref`,t)]}function pn(e){if(e.length===0)throw new R(`a text diff names no path to read`);return e}function mn(e){if(!an(e))throw new R(`${e} is not an object id`);return e}Object.keys(dn([]));function hn(e){let t=dn(un(e.exclude,e.workspace)),n=(e,...n)=>{let r=t[e];if(!r)throw new R(`no git operation named ${String(e)}`);return[...$t.flatMap(e=>[`-c`,e]),...r(...n)]},r=(t,n)=>new Promise((r,i)=>{te(Xt,n,{cwd:e.workspace,env:{...en},encoding:`buffer`,maxBuffer:Qt,timeout:Zt,shell:!1,windowsHide:!0},(e,n,a)=>{let o=Buffer.isBuffer(n)?n:Buffer.from(String(n)),s=gn(a);if(!e)return r({ok:!0,out:o,said:s});let c=e,l=c.code===`ERR_CHILD_PROCESS_STDIO_MAXBUFFER`;if(c.killed||c.code===`ENOENT`||l)return i(new rn(t,s||c.message,l));r({ok:(typeof c.code==`number`?c.code:null)===1&&nn.has(t)&&s.trim()===``,out:o,said:s})})});return{vector:n,async text(e,...t){let i=await r(e,n(e,...t));if(!i.ok)throw new rn(e,i.said||`it said nothing`);return i.out.toString(`utf8`).replace(/\n$/,``)},async bytes(e,...t){let i=await r(e,n(e,...t));if(!i.ok)throw new rn(e,i.said||`it said nothing`);return i.out},async ok(e,...t){return(await r(e,n(e,...t))).ok},async commit(e){let t=await r(`rev-parse`,n(`rev-parse`,e)),i=t.out.toString(`utf8`).trim();if(!t.ok||!an(i))throw new R(`there is no commit at ${e}`);return i}}}function gn(e){return(Buffer.isBuffer(e)?e.toString(`utf8`):String(e)).split(`
|
|
6
|
+
`).map(e=>e.trim()).filter(Boolean)[0]??``}function _n(e){return/^0+$/.test(e)}function vn(e){return!/^0+$/.test(e)}var yn=`#`;function bn(e){return e.path}function xn(e){let t=[];for(let n of e.lines)n.kind===`add`?t.push(`+${n.text}`):n.kind===`remove`&&t.push(`-${n.text}`);return t.join(`
|
|
7
|
+
`)}function Sn(e){return Lt(e)??xn(e)}function Cn(e,t={}){return[`old-oid ${wn(e,`old`,t)}`,`new-oid ${wn(e,`new`,t)}`,`old-mode ${e.oldMode}`,`new-mode ${e.newMode}`,`rename-from ${e.oldPath??``}`,`rename-to ${e.oldPath===null?``:e.path}`,`binary ${e.binary?`yes`:`no`}`].join(`
|
|
8
|
+
`)}function wn(e,t,n){let r=t===`old`?e.oldOid:e.newOid,i=t===`old`?e.oldMode:e.newMode;if(!_n(r)||!vn(i))return r;let a=n.resolveOid?.(e,t)??null;return a===null?r:`content:${a}`}function Tn(e){return S(`sha256`).update(e,`utf8`).digest(`hex`)}function En(e,t={}){let n=[],r=[];return e.files.forEach((e,i)=>{let a=bn(e);e.oldPath!==null&&e.oldPath!==e.path&&r.push({from:e.oldPath,to:e.path});let o=new Map,s=(e,t,r)=>{let s=(o.get(e)??0)+1;o.set(e,s);let c=`${a}${yn}${e}`;n.push({id:`${c}${yn}${s}`,fileKey:a,contentHash:e,ordinal:s,file:i,hunk:r,content:t,nonTextual:r===null})};if(e.hunks.length===0){let n=Cn(e,t);s(Tn(n),n,null);return}e.hunks.forEach((e,t)=>{let n=Sn(e);s(Tn(n),n,t)})}),{entries:n,renames:r,fingerprint:Dn(n.map(e=>e.id))}}function Dn(e){return`sha256:${Tn([...e].sort().join(`
|
|
9
|
+
`))}`}function On(e,t,n){return kn(t,kn(e.map(e=>({from:e.to,to:e.from})),n))}function kn(e,t){let n=new Map(e.map(e=>[e.from,e.to])),r=new Set([t]),i=t;for(;;){let e=n.get(i);if(e===void 0||r.has(e))return i;r.add(e),i=e}}function An(e){let t=e.lastIndexOf(yn);if(t<=0)return null;let n=e.lastIndexOf(yn,t-1);if(n<=0)return null;let r=Number(e.slice(t+1));return!Number.isInteger(r)||r<1?null:{fileKey:e.slice(0,n),contentHash:e.slice(n+1,t),ordinal:r}}function jn(e,t,n){return`${e}#${t}#${n}`}function Mn(e,t){let n=e===``?[]:e.split(`
|
|
10
|
+
`),r=t===``?[]:t.split(`
|
|
11
|
+
`);if(n.length===0&&r.length===0)return 0;let i=new Map;for(let e of n)i.set(e,(i.get(e)??0)+1);let a=0;for(let e of r){let t=i.get(e)??0;t>0&&(i.set(e,t-1),a+=1)}return 1-a/Math.max(n.length,r.length)}function Nn(e,t,n=e=>e){let r=new Set(t.map(e=>e.id)),i=e.filter(e=>!r.has(jn(n(e.fileKey),e.contentHash,e.ordinal))),a=new Set(e.map(e=>jn(n(e.fileKey),e.contentHash,e.ordinal))),o=t.filter(e=>!a.has(e.id));if(i.length===0||o.length===0)return[];let s=new Map,c=new Map,l=new Map,u=(e,t,n)=>{let r=e.get(t);r===void 0?e.set(t,[n]):r.push(n)};for(let e of o){if(e.content===``){l.set(e,0),u(c,e.fileKey,e);continue}let t=e.content.split(`
|
|
12
|
+
`);l.set(e,t.length);for(let n of new Set(t))u(s,`${e.fileKey}\n${n}`,e)}let d=[],f=(e,t)=>Math.abs(e.ordinal-t.ordinal)<=3;for(let e of i){let t=n(e.fileKey);if(e.content===``){for(let n of c.get(t)??[])f(e,n)&&d.push({from:e.id,to:n.id,cost:0});continue}let r=e.content.split(`
|
|
13
|
+
`),i=new Map;for(let e of r)for(let n of s.get(`${t}\n${e}`)??[])i.set(n,(i.get(n)??0)+1);for(let[t,n]of i){if(!f(e,t)||n*2<=Math.max(r.length,l.get(t)??0))continue;let i=Mn(e.content,t.content);i>=.5||d.push({from:e.id,to:t.id,cost:i})}}d.sort((e,t)=>e.cost-t.cost||e.from.localeCompare(t.from)||e.to.localeCompare(t.to));let p=new Set,m=new Set,h=[];for(let e of d)p.has(e.from)||m.has(e.to)||(p.add(e.from),m.add(e.to),h.push(e));return h}function Pn(e){return!an(e.head)}var Fn=[`main`,`master`],In=[`4b825dc642cb6eb9a060e54bf8d69288fbee4904`,`6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321`];async function Ln(e){for(let t of In)if(await e.text(`cat-file-type`,t).catch(()=>``)===`tree`)return t;throw new R(`this repository has no empty tree to diff a first commit against`)}async function Rn(e){return e.ok(`rev-parse-git-dir`)}async function zn(e){let t=await e.text(`rev-parse-abbrev`).catch(()=>``);return t===``||t===`HEAD`?null:t}async function Bn(e){let t=await e.text(`for-each-ref`).catch(()=>``),n=[];for(let e of t.split(`
|
|
14
|
+
`)){if(e===``)continue;let[t=``,r=``,i=``]=e.split(` `);t===``||r===``||n.push({name:t,tip:r,upstream:i===``?null:i})}return n}function Vn(e){let t=[];for(let n of e.split(`
|
|
15
|
+
`)){if(n===``)continue;let e=n.indexOf(` `);e!==-1&&t.push({at:n.slice(0,e),said:n.slice(e+1)})}return t}async function Hn(e,t){let n=[],r=await Bn(e),i=r.find(e=>e.name===t)?.upstream??null,a=e=>Un(e,t,i,new Set(r.map(e=>e.name))),o=Vn(await e.text(`reflog-show`,t).catch(()=>``)).at(-1)?.said??``,s=/^branch: Created from (.+)$/.exec(o)?.[1];s!==void 0&&s!==`HEAD`&&n.push({ref:s,foundBy:`branch-reflog`});let c=Vn(await e.text(`reflog-head`).catch(()=>``));for(let e of[...c].reverse()){let r=/^checkout: moving from (.+) to (.+)$/.exec(e.said);if(r&&r[2]===t&&r[1]!==void 0&&r[1]!==t){n.push({ref:r[1],foundBy:`head-reflog`});break}}i!==null&&n.push({ref:i,foundBy:`upstream`});for(let e of Fn)e!==t&&n.push({ref:e,foundBy:`merge-base`});for(let r of n){if(a(r.ref))continue;let n=await Wn(e,r.ref,t);if(n!==null)return{ref:r.ref,hash:n,foundBy:r.foundBy}}return null}function Un(e,t,n,r){return e===t||e===`refs/heads/${t}`?!0:e.endsWith(`/${t}`)?e.startsWith(`refs/remotes/`)?!0:e===n&&!r.has(e):!1}async function Wn(e,t,n){let r=(await e.text(`merge-base`,t,n).catch(()=>``)).trim();return an(r)?r:null}async function Gn(e,t,n){return e.ok(`merge-base-ancestor`,t,n)}function Kn(e){let t=(Buffer.isBuffer(e)?e.toString(`utf8`):e).split(`\0`),n=[];for(let e=0;e<t.length;e+=1){let r=t[e];if(r===void 0||r===``)continue;let i=r.slice(0,2),a=r.slice(3);if(a===``)continue;let o=i.includes(`R`)||i.includes(`C`),s=o?t[e+1]??null:null;o&&(e+=1),n.push({code:i,path:a,oldPath:s,untracked:i===`??`})}return n}async function qn(e){return Kn(await e.bytes(`status`))}async function Jn(e){return(await e.bytes(`ls-files-others`)).toString(`utf8`).split(`\0`).filter(e=>e!==``)}function Yn(e){let t=[];for(let n of e.split(`
|
|
16
|
+
`)){if(n===``)continue;let e=n.split(` `);e.length<5||t.push({hash:e[0]??``,parents:(e[1]??``).split(` `).filter(e=>e!==``),author:e[2]??``,date:e[3]??``,subject:e.slice(4).join(` `)})}return t}async function Xn(e,t,n){let r=Zn(n.base)?null:n.base,i=Pn(t)?`log`:`log-first-parent`;return Yn(await e.text(i,r,n.head).catch(()=>``))}function Zn(e){return In.includes(e)}async function Qn(e,t){let n=await er(e,t);if(Pn(t))return{base:n,head:await e.commit(t.head),tree:t.uncommitted,extended:!1,rewritten:!1};if(t.followed!==null)return{base:n,head:t.followed,tree:!1,extended:!1,rewritten:!1};let r=await e.commit(`HEAD`).catch(()=>null);if(!(r!==null&&await Gn(e,t.head,r)))return{base:n,head:t.head,tree:t.uncommitted,extended:!1,rewritten:r!==null};let i=await $n(e,t.head,r),a=i!==t.head;return{base:n,head:i,tree:t.uncommitted,extended:a,rewritten:!1}}async function $n(e,t,n){if(t===n)return n;let r=Yn(await e.text(`log-first-parent`,t,n).catch(()=>``)),i=t;for(let e of[...r].reverse()){if(e.parents.length>1)return i;i=e.hash}return i}async function er(e,t){return!((t.kind===`branch`||t.kind===`other-branch`)&&t.baseRef!==null&&t.baseFoundBy!==`chosen`)||t.baseRef===null?t.base:await Wn(e,t.baseRef,t.head)??t.base}async function tr(e,t){let n=t.base===void 0?null:await e.commit(t.base);if(t.kind===`branch`||t.kind===`other-branch`){let r=t.branch??await zn(e);if(r===null)throw new R(`there is no branch checked out`);let i=await e.commit(r),a=n===null?await Hn(e,r):{ref:t.base??null,hash:n,foundBy:`chosen`};if(a===null)throw new R(`the base of ${r} could not be found`);if(a.hash===i)throw new R(`${r} holds nothing its base does not`);return{kind:t.kind,base:a.hash,baseRef:a.ref,baseFoundBy:a.foundBy,head:r,uncommitted:t.kind===`branch`?t.uncommitted??!1:!1,followed:null}}if(t.kind===`range`){if(t.from===void 0||t.to===void 0)throw new R(`a range names both of its ends`);let r=n??await e.commit(t.from),i=await e.commit(t.to);if(r===i)throw new R(`the range is empty`);return{kind:`range`,base:r,baseRef:n===null?t.from:t.base??null,baseFoundBy:n===null?`range`:`chosen`,head:i,uncommitted:t.uncommitted??!1,followed:null}}let r=t.kind===`last-commit`?`HEAD`:t.commit??``;if(r===``)throw new R(`no commit was named`);let i=await e.commit(r);if(n!==null)return{kind:t.kind,base:n,baseRef:t.base??null,baseFoundBy:`chosen`,head:i,uncommitted:t.uncommitted??!1,followed:null};let a=await e.commit(`${i}^`).catch(()=>null);return{kind:t.kind,base:a??await Ln(e),baseRef:null,baseFoundBy:a===null?`root`:`parent`,head:i,uncommitted:t.uncommitted??!1,followed:null}}async function nr(e,t){let n=await e.commit(t),r=await e.commit(`${n}^`).catch(()=>null);return{kind:`commit`,base:r??await Ln(e),baseRef:null,baseFoundBy:r===null?`root`:`parent`,head:n,uncommitted:!1,followed:n}}async function rr(e,t){let n=await Qn(e,t),r=L(await e.bytes(`diff`,n.base,n.tree?null:n.head,n.tree)),i=r.files.length,a=0,o=0,s=0;for(let e of r.files){a+=e.hunks.length===0?1:e.hunks.length;let t=Yt(e);o+=t.added,s+=t.deleted}if(n.tree)for(let t of await Jn(e)){let n=L(await e.bytes(`diff-no-index`,t));for(let e of n.files){let t=Yt(e);a+=e.hunks.length===0?1:e.hunks.length,o+=t.added,s+=t.deleted}i+=n.files.length}return{files:i,hunks:a,added:o,deleted:s,commits:await Xn(e,t,n),uncommittedFiles:t.uncommitted?(await qn(e)).length:0}}async function ir(e){let t={options:[],notOffered:null};if(!await Rn(e)||await e.commit(`HEAD`).catch(()=>null)===null)return t;let n=[],r=(await qn(e)).length,i=await zn(e),a=async t=>{try{return n.push(await or(e,t,r)),null}catch(e){return e instanceof Error?e:Error(String(e))}},o=null;if(i!==null){let e=await a({kind:`branch`,uncommitted:r>0});e!==null&&(o={branch:i,reason:e.message})}await a({kind:`last-commit`});for(let t of await Bn(e))t.name!==i&&await a({kind:`other-branch`,branch:t.name});return{options:n,notOffered:o}}async function ar(e,t){return or(e,t,(await qn(e)).length)}async function or(e,t,n){let r=await tr(e,t);return{kind:r.kind,label:sr(r),selection:r,summary:await rr(e,r),uncommitted:{offered:r.kind===`branch`,files:n}}}function sr(e){let t=e=>e.slice(0,12);return e.kind===`branch`||e.kind===`other-branch`?`${e.head} against ${e.baseRef??t(e.base)}`:e.kind===`last-commit`?`the last commit, ${t(e.head)}`:e.kind===`range`?`${t(e.base)}..${t(e.head)}`:`commit ${t(e.head)}`}var cr=[`package-lock.json`,`pnpm-lock.yaml`,`yarn.lock`,`Cargo.lock`,`go.sum`,`poetry.lock`,`Gemfile.lock`,`composer.lock`],lr=200;async function ur(e,t){let n=new Set;for(let r=0;r<t.length;r+=lr){let i=(await e.text(`check-attr`,t.slice(r,r+lr))).split(`\0`);for(let e=0;e+2<i.length;e+=3){let t=i[e],r=i[e+2];t!==void 0&&t!==``&&r===`set`&&n.add(t)}}return n}function dr(e,t,n){if(e.binary)return`binary`;let r=e.path.split(`/`).pop()??e.path;return cr.includes(r)||t.has(e.path)?`generated`:n.added+n.deleted>5e3?`oversize`:`text`}async function fr(e,t){let n=t.filter(e=>!e.binary).map(e=>e.path),r=n.length===0?new Set:await ur(e,n),i=new Map;for(let e of t){let t=Yt(e),n=dr(e,r,t);i.set(e,{category:n,added:t.added,deleted:t.deleted}),n!==`text`&&(e.hunks=[])}return i}var pr={hunks:2e3,patchBytes:20*1024*1024,blobBytes:100*1024*1024},mr=class extends Error{code=`too-large`;constructor(e){super(`reviews: ${e}`),this.name=`TooLarge`}};function hr(e){return S(`sha256`).update(e).digest(`hex`)}function gr(e,t){if(t===``||t.startsWith(`/`)||t.split(`/`).includes(`..`))throw new R(`${t} is not a path inside the workspace`);return y(e,t)}function _r(e,t){try{return i(y(e,t)).isFile()}catch{return!1}}async function vr(e,t,n){let r={...pr,...n.limits},i=await Qn(e,t),a=await yr(e,i,n.workspace,r.blobBytes).catch(e=>{throw e instanceof rn&&e.tooMuch?new mr(`this selection holds more than ${B(Qt)} of diff; a narrower selection will open`):e}),o=a.parsed,s=[...a.patches],c=new Set;if(i.tree)for(let t of(await Jn(e)).sort()){if(!_r(n.workspace,t))continue;let r=await e.bytes(`diff-no-index`,t);s.push(r);for(let e of L(r).files)o.files.push(e),c.add(e.path)}let l=s.reduce((e,t)=>e+t.length,0);if(l>r.patchBytes)throw new mr(`this selection holds ${B(l)} of diff, past the limit of ${B(r.patchBytes)}; a narrower selection will open`);let u=await fr(e,o.files),d=await wr(e,o,n.workspace,r.blobBytes,i.tree),f=En(o,{resolveOid:(e,t)=>d.hashes.get(e)?.[t]??null});if(f.entries.length>r.hunks)throw new mr(`this selection holds ${f.entries.length} hunks, past the limit of ${r.hunks}; a narrower selection will open`);let p=o.files.map(e=>{let t=u.get(e)??{category:`text`,...Yt(e)},n=d.stored.get(e)??{old:null,new:null},r=e=>e===null?null:d.blobs.get(e)?.length??null;return{path:e.path,oldPath:e.oldPath,status:e.status,similarity:e.similarity,oldMode:e.oldMode,newMode:e.newMode,oldOid:e.oldOid,newOid:e.newOid,binary:e.binary,category:t.category,oldBlob:n.old,newBlob:n.new,oldBytes:r(n.old),newBytes:r(n.new),added:t.added,deleted:t.deleted,hunks:e.hunks,untracked:c.has(e.path)}}),m=f.entries.map(e=>({id:e.id,fileKey:e.fileKey,contentHash:e.contentHash,ordinal:e.ordinal,file:e.file,hunk:e.hunk,facts:e.nonTextual?e.content:null}));return{record:{version:1,computedAt:new Date().toISOString(),selection:t,resolved:i,commits:await Xn(e,t,i),tree:i.tree?await Er(e,o,n.workspace,r.blobBytes):null,files:p,entries:m,renames:f.renames,fingerprint:f.fingerprint,totals:{files:p.length,hunks:m.length,added:p.reduce((e,t)=>e+t.added,0),deleted:p.reduce((e,t)=>e+t.deleted,0),patchBytes:l,blobBytes:d.bytes}},patch:Buffer.concat(s),blobs:d.blobs}}function B(e){return`${(e/(1024*1024)).toFixed(1)} MB`}async function yr(e,t,n,r){let i=t.tree?null:t.head,a=await e.bytes(`diff`,t.base,i,t.tree),o=L(a),s=[];for(let i of o.files)i.binary&&await br(e,i,n,r,t.tree)&&(i.oldPath!==null&&s.push(i.oldPath),s.push(i.path));if(s.length===0)return{parsed:o,patches:[a]};let c=await e.bytes(`diff`,t.base,i,t.tree,s),l=await e.bytes(`diff-text`,t.base,i,t.tree,s);return{parsed:{files:[...L(c).files,...L(l).files]},patches:[c,l]}}async function br(e,t,n,r,i){for(let a of[`old`,`new`]){let o=a===`old`?t.oldMode:t.newMode;if(/^0+$/.test(o)||o===`160000`)continue;let s=await xr(e,t,a,n,r,i).catch(()=>null);if(s===null||s.subarray(0,Cr).includes(0))return!1}return!0}async function xr(e,t,n,r,i,a){let o=n===`old`?t.oldOid:t.newOid;return Sr(n,o,a)?Tr(r,n===`old`?t.oldPath??t.path:t.path,i):e.bytes(`cat-file-blob`,o)}function Sr(e,t,n){return n&&e===`new`||/^0+$/.test(t)}var Cr=8e3;async function wr(e,t,n,r,i){let a={blobs:new Map,stored:new Map,hashes:new Map,bytes:0};for(let o of t.files){let t={old:null,new:null},s={old:null,new:null};for(let c of[`old`,`new`]){let l=c===`old`?o.oldOid:o.newOid,u=c===`old`?o.oldMode:o.newMode;if(/^0+$/.test(u)||u===`160000`)continue;let d=Sr(c,l,i),f=await xr(e,o,c,n,r,i);if(f===null)continue;let p=d?hr(f):l;if(d&&(s[c]=p),t[c]=p,!a.blobs.has(p)){if(a.bytes+=f.length,a.bytes>r)throw new mr(`this selection holds ${B(a.bytes)} of file content, past the limit of ${B(r)}; a narrower selection will open`);a.blobs.set(p,f)}}a.stored.set(o,t),a.hashes.set(o,s)}return a}function Tr(e,t,n){let r=gr(e,t),a;try{a=i(r)}catch{return null}if(a.isSymbolicLink())return Buffer.from(l(r),`utf8`);if(!a.isFile())return null;if(a.size>n)throw new mr(`${t} is ${B(a.size)}, past the limit of ${B(n)} for one file; a narrower selection will open`);return s(r)}async function Er(e,t,n,r){let a=(await e.bytes(`status`)).toString(`utf8`),o=[],s=new Set;for(let e of t.files){if(s.has(e.path)||/^0+$/.test(e.newMode)||e.newMode===`160000`)continue;s.add(e.path);let t=gr(n,e.path),a=Tr(n,e.path,r);if(a===null)continue;let c;try{c=i(t)}catch{continue}o.push({path:e.path,size:a.length,mtimeMs:c.mtimeMs,hash:hr(a)})}return{porcelain:a,files:o}}function Dr(e){return y(e,C)}function Or(e){return y(Dr(e),T)}function kr(e){return y(Or(e),_e)}function Ar(e,t){let n=Dr(e),r=y(n,fe);f(r,{recursive:!0,force:!0}),a(y(r,ge),{recursive:!0});for(let[e,n]of t.blobs)P(Ir(r,e),n);P(y(r,he),t.patch),P(y(r,me),`${JSON.stringify(t.record,null,2)}\n`),jr(n)}function jr(e){let t=y(e,T),r=y(e,fe),i=y(e,pe);n(t)&&(f(i,{recursive:!0,force:!0}),d(t,i)),d(r,t),f(i,{recursive:!0,force:!0})}function Mr(e){let t=Dr(e),r=y(t,T),i=y(t,fe),a=y(t,pe),o=n(y(i,me));if(n(r)){f(a,{recursive:!0,force:!0}),o||f(i,{recursive:!0,force:!0});return}if(o){jr(t);return}f(i,{recursive:!0,force:!0}),n(a)&&d(a,r)}function Nr(e){let t=y(Dr(e),T,me);if(!n(t))return null;let r;try{r=JSON.parse(s(t,`utf8`))}catch{return null}if(!Pr(r))return null;try{on(r.resolved.base),on(r.resolved.head)}catch{return null}return r}function Pr(e){if(typeof e!=`object`||!e||!Array.isArray(e.files)||!Array.isArray(e.entries)||!Array.isArray(e.commits))return!1;let t=e.resolved;return typeof t==`object`&&!!t&&typeof t.base==`string`&&typeof t.head==`string`&&typeof e.fingerprint==`string`&&typeof e.selection==`object`&&e.selection!==null}function Fr(e){if(!/^[0-9a-f]{40}$|^[0-9a-f]{64}$/.test(e))throw new N(`reviews`,e);return`${C}/${T}/${ge}/${e}`}function Ir(e,t){if(!/^[0-9a-f]{40}$|^[0-9a-f]{64}$/.test(t))throw new N(`reviews`,t);return y(e,ge,t)}function Lr(e){return e.entries.map(t=>({id:t.id,fileKey:t.fileKey,contentHash:t.contentHash,ordinal:t.ordinal,content:Rr(e,t)}))}function Rr(e,t){if(t.facts!==null)return t.facts;let n=t.hunk===null?void 0:e.files[t.file]?.hunks[t.hunk];return n===void 0?``:xn(n)}function zr(e,t){let n=new Set(t.entries.map(e=>e.id)),r=Vr(e,t),i=new Map,a=new Set;for(let t of e.entries){let e=Br(r(t.fileKey),t.contentHash,t.ordinal);n.has(e)&&(i.set(t.id,e),a.add(e))}let o=Nn(Lr(e),Lr(t),r),s=new Map;for(let e of o)i.set(e.from,e.to),s.set(e.to,e.from);let c=new Set(i.values()),l=new Set;for(let n of Hr(e,t,r)){let e=i.get(n);e!==void 0&&l.add(e)}return{lineage:i,same:a,paired:s,vanished:e.entries.filter(e=>!i.has(e.id)).map(e=>e.id),arrived:t.entries.filter(e=>!c.has(e.id)).map(e=>e.id),reset:l}}function Br(e,t,n){return`${e}#${t}#${n}`}function Vr(e,t){let n=new Map;return r=>{let i=n.get(r);if(i!==void 0)return i;let a=On(e.renames,t.renames,r);return n.set(r,a),a}}function Hr(e,t,n){let r=(e,t)=>{let n=new Map;for(let r of e.entries){let e=`${t(r.fileKey)}#${r.contentHash}`;n.set(e,(n.get(e)??0)+1)}return n},i=e=>e,a=r(e,n),o=r(t,i),s=new Set;for(let t of e.entries){let e=`${n(t.fileKey)}#${t.contentHash}`;(a.get(e)??0)!==(o.get(e)??0)&&s.add(t.id)}return s}var Ur={done:`Agent done`,sync:`Synced`,stop:`Stopped`,follow:`Followed`};function Wr(e,t){let n=[];return t.changedSeen>0&&n.push(t.changedSeen===1?`1 hunk changed since you saw it`:`${t.changedSeen} hunks changed since you saw them`),t.threadsAnswered>0&&n.push(t.threadsAnswered===1?`1 thread answered`:`${t.threadsAnswered} threads answered`),t.newCommits>0&&n.push(t.newCommits===1?`1 new commit`:`${t.newCommits} new commits`),n.length===0?null:`${Ur[e]}: ${n.join(`, `)}`}function Gr(e,t){if(e===null)return 0;let n=new Set(e.commits.map(e=>e.hash));return t.commits.filter(e=>!n.has(e.hash)).length}var V=`reviews`;function Kr(e,t){return yt(V,e,t)}function qr(e,t){return bt(V,e,t)}var H=class extends Error{code=`bad-request`;constructor(e){super(`reviews: ${e}`),this.name=`Refused`}},Jr=new Map;function U(e,t){let n=(Jr.get(e)??Promise.resolve()).then(t,t),r=n.then(()=>void 0,()=>void 0);return Jr.set(e,r),r.then(()=>{Jr.get(e)===r&&Jr.delete(e)}),n}function Yr(e){let t=e.split(`/`);return t.length===2&&t[0]===`archive`}function Xr(e){let t=e.split(`/`);return t.some(e=>e===``||e===`.`||e===`..`)?!1:t.length===1?t[0]!==w:Yr(e)}function W(e,t){let n=t.trim();if(!Xr(n))throw new N(V,t);return Kr(e,n)}function Zr(e,t,n){return qr(e,`${G(t)}/${C}/${n}`)}function G(e){let t=e.trim();if(!Xr(t))throw new N(V,e);return t}function K(e,t,n){return Mt(V,e,`${G(t)}/${C}/${n}`)}function q(e,t,n,r){jt(V,e,`${G(t)}/${C}/${n}`,r)}function J(e){return`${JSON.stringify(e,null,2)}\n`}function Qr(e){a(e,{recursive:!0});let t=qr(e,`.gitignore`);n(t)||P(t,`${ye.join(`
|
|
17
|
+
`)}\n`)}function $r(e,t,r){let i=r(t)||`review`;if(!n(Kr(e,i)))return i;let a=2;for(;n(Kr(e,`${i}-${a}`));)a++;return`${i}-${a}`}function ei(e,t,r=new Date().toISOString()){let i=W(e,t);if(!n(i)||!p(i).isDirectory())throw new st(V,t);let a=G(t),o=a.split(`/`).pop()??a,s=Nr(i),c=it(K(e,t,re),o);if(c===null)throw new st(V,`${t}/${C}/${re}`);let l=K(e,t,ie),u=K(e,t,ae),d=K(e,t,oe),f=K(e,t,se),m=ni(e,a,[[ie,l],[ae,u],[oe,d],[se,f]]),h=Fe(l),g=Le(u),_=ze(d),v=Ue(f),y=!1,ee=oi(i),b=s!==null&&[h.fingerprint,g.fingerprint,_.fingerprint,v.fingerprint].some(e=>e!==s.fingerprint);if(s!==null&&b){let e=Ci(s,{marks:h,threads:g,pending:_,dismissals:v},r);h=e.marks,g=e.threads,_=e.pending,v=e.dismissals,y=!0}let x=c,S=fi(e,a),te=ii(x,S,s,r);return{slug:a,dir:i,state:c,marks:h,threads:g,pending:_,dismissals:v,metadata:ee,approval:Ye(K(e,t,le)),baseline:s,loops:S.length,repaired:y||te,broken:m}}function ti(e){if(e===null||e.trim()===``)return!1;try{let t=JSON.parse(e);return typeof t!=`object`||!t||Array.isArray(t)}catch{return!0}}function ni(e,t,n){let r=n.filter(([,e])=>ti(e)).map(([e])=>e);if(r.length===0||Yr(t))return r;for(let n of r)d(Zr(e,t,n),Zr(e,t,ri(e,t,n)));return r}function ri(e,t,r){let i=r.replace(/\.json$/,``),a=`${i}.broken.json`,o=2;for(;n(Zr(e,t,a));)a=`${i}.broken-${o}.json`,o++;return a}function ii(e,t,n,r){let i=t[t.length-1]??null,a=t=>e.log.some(e=>e.said===t),o=!1;return i!==null&&e.status===`reviewing`&&e.side===`you`&&n!==null&&i.fingerprint===n.fingerprint&&!a(ai(i.items.length,t.length))&&(e.side=`agent`,e.agent={act:`process`,activity:`Working on your feedback`,groups:null,lastPostAt:r},e.log.push({at:r,said:ai(i.items.length,t.length)}),o=!0),o}function ai(e,t){return`Sent to agent: ${e} ${e===1?`item`:`items`} - loop ${t}.`}function oi(e){try{return Ge(s(kr(e),`utf8`))}catch{return We()}}function si(e,t,n=[]){if(Yr(t.slug)&&t.state.status===`archived`)throw new H(`${t.slug} is archived, so nothing is written into it`);let r=t.baseline?.fingerprint??``,i=new Set(n);i.has(`marks`)&&(t.marks.fingerprint=r,q(e,t.slug,ie,J(t.marks))),i.has(`threads`)&&(t.threads.fingerprint=r,q(e,t.slug,ae,J(t.threads))),i.has(`pending`)&&(t.pending.fingerprint=r,q(e,t.slug,oe,J(t.pending))),i.has(`dismissals`)&&(t.dismissals.fingerprint=r,q(e,t.slug,se,J(t.dismissals))),i.has(`metadata`)&&(a(Or(t.dir),{recursive:!0}),P(kr(t.dir),J(t.metadata))),i.has(`approval`)&&t.approval!==null&&q(e,t.slug,le,J(t.approval)),q(e,t.slug,re,J(t.state)),P(Kr(e,`${t.slug}/README.md`),ci(t))}function ci(e){let t=hi(e);return Ce({state:e.state,seen:t.seen,total:t.total,loops:e.loops,fingerprint:e.baseline?.fingerprint??``,commit:e.baseline?.resolved.head??``,threads:{total:e.threads.threads.length,open:e.threads.threads.filter(e=>e.open).length},metadata:e.metadata,approval:e.approval})}function li(e,t){return qe(K(e,t,ce))}function ui(e,t,n){q(e,t,ce,J(n))}function di(e,t){return Zr(e,t,ue)}function fi(e,t){let r=y(W(e,t),C,de);if(!n(r))return[];let i=c(r).filter(e=>/^\d+\.json$/.test(e)).sort(),a=[];for(let n of i){let r=Be(K(e,t,`${de}/${n}`));r!==null&&a.push(r)}return a}function pi(e,t,r){let i=y(W(e,t),C,de),a=(n(i)?c(i).filter(e=>/^\d+\.json$/.test(e)):[]).reduce((e,t)=>Math.max(e,Number.parseInt(t,10)),0),o=`${String(a+1).padStart(2,`0`)}.json`;return q(e,t,`${de}/${o}`,J(r)),`${de}/${o}`}function mi(e,t,r){let i=Kr(e,r);if(n(i))throw new H(`${r} is already there`);a(_(i),{recursive:!0}),d(W(e,t),i)}function hi(e){let t=e.baseline?.entries.length??0;if(e.baseline===null)return{seen:0,total:0,left:0};let n=new Set(e.baseline.entries.map(e=>e.id)),r=new Set(e.marks.marks.map(e=>e.hunk).filter(e=>n.has(e)));return{seen:r.size,total:t,left:t-r.size}}function gi(e){let t=new Set(e.dismissals.items.map(e=>je(e.hunk,e.key)));return e.metadata.notes.filter(e=>!t.has(je(e.hunk,e.key)))}function _i(e){let t=e.threads.threads,n=gi(e);return{unreadReplies:t.reduce((e,t)=>e+we(t),0),issues:n.filter(e=>e.kind===`issue`).length,attention:n.filter(e=>e.kind===`attention`).length,changed:e.marks.changed.length,removed:t.filter(e=>e.open&&e.label===`hunk-removed`).length,waiting:e.state.side===`agent`?0:t.filter(e=>e.open&&e.messages[e.messages.length-1]?.from===`agent`).length}}function vi(e){if(e.state.status!==`reviewing`||e.state.side!==`you`||e.baseline===null)return!1;let t=hi(e);return t.total===0||t.left>0||e.threads.threads.some(e=>e.open)?!1:e.pending.items.length===0}function yi(e,t){if(e===null)return[];let n=new Set;for(let e of t.groups)if(e.id!==`ungrouped`)for(let t of e.hunks)n.add(t);return e.entries.map(e=>e.id).filter(e=>!n.has(e))}function bi(e,t,n,r,i){return xi(zr(e,t),t,n,r,i)}function xi(e,t,n,r,i){let a=new Set(t.entries.map(e=>e.id)),o=t=>{let n=e.lineage.get(t);return n!==void 0&&a.has(n)?n:null},s=[],c=[];for(let t of n.marks.marks){let n=o(t.hunk);if(n!==null){if(e.same.has(n)&&!e.reset.has(n)){s.push({...t,hunk:n});continue}e.paired.has(n)&&c.push({hunk:n,at:i,content:t.content})}}let l=c.length,u=new Set(c.map(e=>e.hunk));for(let e of n.marks.changed){let t=o(e.hunk);t===null||u.has(t)||c.push({...e,hunk:t})}let d=n.threads.threads.map(e=>{if(e.kind===`group`)return{...e};let t=o(e.anchor);return t===null?{...e,label:`hunk-removed`}:{...e,anchor:t,label:null}}),f=n.pending.items.map(e=>{if(e.hunk===null)return{...e};let t=o(e.hunk);return t===null?{...e,label:`hunk-removed`}:{...e,hunk:t,label:null}}),p=Si(e,a,r,t.fingerprint),m=new Set(p.notes.map(e=>je(e.hunk,e.key))),h=[];for(let e of n.dismissals.items){let t=o(e.hunk);t!==null&&m.has(je(t,e.key))&&h.push({...e,hunk:t})}return{marks:{...n.marks,marks:s,changed:c,fingerprint:t.fingerprint},threads:{...n.threads,threads:d,fingerprint:t.fingerprint},pending:{...n.pending,items:f,fingerprint:t.fingerprint},dismissals:{...n.dismissals,items:h,fingerprint:t.fingerprint},metadata:p,changedSeen:l}}function Si(e,t,n,r){let i=n=>{let r=e.lineage.get(n);return r!==void 0&&t.has(r)?r:null};return{...n,fingerprint:r,groups:n.groups.map(e=>({...e,hunks:e.hunks.map(e=>i(e)).filter(e=>e!==null)})),notes:n.notes.map(t=>{let n=i(t.hunk);return n!==null&&e.same.has(n)&&!e.reset.has(n)?{...t,hunk:n}:null}).filter(e=>e!==null)}}function Ci(e,t,n){let r=[];for(let e of t.marks.marks){let t=An(e.hunk);t!==null&&r.push({id:e.hunk,fileKey:t.fileKey,contentHash:t.contentHash,ordinal:t.ordinal,content:e.content})}let i=new Set(e.entries.map(e=>e.id)),a=Lr(e),o=new Set,s=new Map;for(let e of r)i.has(e.id)&&(o.add(e.id),s.set(e.id,e.id));let c=new Map;for(let e of Nn(r,a))s.set(e.from,e.to),c.set(e.to,e.from);for(let e of i)s.has(e)||s.set(e,e);for(let e of o)s.set(e,e);return xi({lineage:s,same:o,paired:c,vanished:[],arrived:[],reset:new Set},e,t,We(),n)}function wi(e,t){let n=0;for(let r of t){if(!r.startsWith(e))continue;let t=Number(r.slice(e.length));Number.isInteger(t)&&t>n&&(n=t)}return`${e}${n+1}`}function Ti(e,t,n){let r=e.threads.find(e=>e.open&&e.kind===t&&e.anchor===n);if(r!==void 0)return{thread:r,added:!1};let i={id:wi(`t`,e.threads.map(e=>e.id)),kind:t,anchor:n,open:!0,label:null,closedAt:null,messages:[]};return e.threads.push(i),{thread:i,added:!0}}function Ei(e,t,n,r,i){let a={id:wi(`m`,e.threads.flatMap(e=>e.messages.map(e=>e.id))),from:n,at:i,text:r,readAt:n===`agent`?null:i};return t.messages.push(a),a}function Di(e){return{marks:Pe(e),threads:Ie(e),pending:Re(e),dismissals:He(e)}}var Y=(e=[])=>({wrote:e,typed:[],command:!1});function X(e,t){if(e.state.status!==`reviewing`)throw new H(`this review is ${e.state.status}, so ${t} is not possible`);if(e.state.side!==`you`)throw new H(`this review awaits the agent, so ${t} is not possible`)}function Oi(e,t){let n=e.baseline;if(n===null)throw new H(`this review has no baseline`);let r=n.entries.find(e=>e.id===t);if(r===void 0)throw new H(`this review holds no hunk ${t}`);return{baseline:n,entry:r}}function ki(e,t,n){X(e,`marking a hunk`);let{baseline:r,entry:i}=Oi(e,t.hunk),a=e.marks;if(!t.seen)return a.marks.some(e=>e.hunk===t.hunk)?(Mi(e,`unseen`,null,[t.hunk],n),a.marks=a.marks.filter(e=>e.hunk!==t.hunk),a.changed=a.changed.filter(e=>e.hunk!==t.hunk),Y([`marks`])):Y([]);let o=Mi(e,`hunk`,null,[t.hunk],n),s={hunk:t.hunk,at:n,act:o,content:Rr(r,i)};return a.marks=[...a.marks.filter(e=>e.hunk!==t.hunk),s],a.changed=a.changed.filter(e=>e.hunk!==t.hunk),Y([`marks`])}function Ai(e,t,n){X(e,`marking a group`);let r=e.baseline;if(r===null)throw new H(`this review has no baseline`);let i=ji(e,t),a=new Set(e.marks.marks.map(e=>e.hunk)),o=i.filter(e=>!a.has(e));if(o.length===0)throw new H(`nothing is left to mark in ${t.id}`);let s=Mi(e,t.kind,t.id,o,n),c=new Map(r.entries.map(e=>[e.id,e]));for(let t of o){let i=c.get(t);i!==void 0&&e.marks.marks.push({hunk:t,at:n,act:s,content:Rr(r,i)})}let l=new Set(o);return e.marks.changed=e.marks.changed.filter(e=>!l.has(e.hunk)),Y([`marks`])}function ji(e,t){let n=e.baseline;if(n===null)return[];if(t.kind===`file`)return n.entries.filter(e=>e.fileKey===t.id).map(e=>e.id);if(t.id===`ungrouped`)return yi(n,e.metadata);let r=e.metadata.groups.find(e=>e.id===t.id);if(r===void 0)throw new H(`this review holds no group ${t.id}`);let i=new Set(n.entries.map(e=>e.id));return r.hunks.filter(e=>i.has(e))}function Mi(e,t,n,r,i){let a=wi(`a`,e.marks.acts.map(e=>e.id));return e.marks.acts.push({id:a,at:i,kind:t,container:n,hunks:r}),a}function Ni(e,t,n){X(e,`commenting`);let{baseline:r,entry:i}=Oi(e,t.hunk);if(t.kind===`talk`){let{thread:a}=Ti(e.threads,`hunk`,t.hunk);Ei(e.threads,a,`tool`,`Conversation request sent to the agent in the terminal.`,n);let o=r.files[i.file],s=i.hunk===null?null:o?.hunks[i.hunk]??null,c=t.lines===null?``:Oe(t.lines);return{wrote:[`threads`],typed:[{event:`talk`,detail:[e.state.name,o?.path??i.fileKey,s?.header??`the whole file`,c].filter(e=>e!==``).join(` - `),path:`${e.slug}/${C}/${ae}`}],command:!1}}if(t.kind===`group-comment`)throw new H(`a group comment names its group, so it is posted as one`);return Fi(e,t.kind,t.hunk,null,t.lines,t.text,n),Y([`pending`])}function Pi(e,t,n){if(X(e,`commenting`),!(t.group===`ungrouped`||e.metadata.groups.some(e=>e.id===t.group)))throw new H(`this review holds no group ${t.group}`);return Fi(e,`group-comment`,null,t.group,null,t.text,n),Y([`pending`])}function Fi(e,t,n,r,i,a,o){let s=a.trim();if(s===``&&De(t))throw new H("say something in `text`");let c={id:wi(`p`,e.pending.items.map(e=>e.id)),at:o,act:t,hunk:n,group:r,lines:i!==null&&i.length>0?[...i]:null,text:s,label:null};return e.pending.items.push(c),c}function Ii(e,t,n){X(e,`changing the pending feedback`);let r=e.baseline;if(r===null)throw new H(`this review has no baseline`);let i=new Set(r.entries.map(e=>e.id)),a=new Set([Me,...e.metadata.groups.map(e=>e.id)]),o=[];for(let e of t){if(e.hunk!==null&&!i.has(e.hunk)){o.push({...e,label:`hunk-removed`});continue}if(e.group!==null&&!a.has(e.group))throw new H(`this review holds no group ${e.group}`);o.push({...e,at:e.at||n,label:null})}return e.pending.items=o,e.pending.version=1,Y([`pending`])}function Li(e,t,n){if(X(e,`dismissing a note`),!e.metadata.notes.some(e=>e.hunk===t.hunk&&e.key===t.key))throw new H(`this review holds no such note`);let r=e.dismissals.items.filter(e=>!(e.hunk===t.hunk&&e.key===t.key));return e.dismissals.items=t.on?[...r,{hunk:t.hunk,key:t.key,at:n}]:r,Y([`dismissals`])}function Ri(e,t,n){X(e,`closing a thread`);let r=e.threads.threads.find(e=>e.id===t);if(r===void 0)throw new H(`there is no thread called ${t}`);r.open=!1,r.closedAt=n;for(let e of r.messages)e.readAt===null&&(e.readAt=n);return Y([`threads`])}function zi(e,t,n){if(t.length===0)return Y();let r=new Set(t),i=!1;for(let t of e.threads.threads)for(let e of t.messages)e.readAt!==null||!r.has(e.id)||(e.readAt=n,i=!0);return Y(i?[`threads`]:[])}function Bi(e,t,n){X(t,`sending`);let r=t.pending.items;if(r.length===0)throw new H(`there is nothing to send`);let i=t.baseline?.fingerprint??``,a=r.map(e=>({hunk:e.hunk,act:e.act,group:e.group,lines:e.lines,text:e.text})),o={version:1,sentAt:n,fingerprint:i,items:a};pi(e.root,t.slug,o),t.loops+=1;for(let e of r){let r=e.hunk??e.group;if(r===null)continue;let{thread:i}=Ti(t.threads,e.hunk===null?`group`:`hunk`,r),a=e.lines===null?``:` ${Oe(e.lines)}`,o=`${Ee[e.act]}${a}`;Ei(t.threads,i,`you`,e.text?`${o}: ${e.text}`:o,n)}return t.pending.items=[],Vi(t,`process`,`Working on your feedback`,n),t.state.log.push({at:n,said:ai(a.length,t.loops)}),{wrote:[`pending`,`threads`],typed:[],command:!0}}function Vi(e,t,n,r){e.state.side=`agent`,e.state.agent={act:t,activity:n,groups:null,lastPostAt:r}}async function Hi(e,t,n,r){let i=t.baseline,a=await vr(e.git,t.state.selection,{workspace:e.workspace,limits:e.limits}),o=0;if(i!==null){let e=bi(i,a.record,{marks:t.marks,threads:t.threads,pending:t.pending,dismissals:t.dismissals},t.metadata,r);t.marks=e.marks,t.threads=e.threads,t.pending=e.pending,t.dismissals=e.dismissals,t.metadata=e.metadata,o=e.changedSeen}Ar(t.dir,a),t.baseline=a.record;let s=Wr(n,{changedSeen:o,threadsAnswered:Ui(t,i),newCommits:Gr(i,a.record)});return s!==null&&t.state.log.push({at:r,said:s}),{wrote:[`marks`,`threads`,`pending`,`dismissals`,`metadata`],typed:[],command:!1,line:s}}function Ui(e,t){if(t===null)return 0;let n=Date.parse(t.computedAt);return Number.isNaN(n)?0:e.threads.threads.filter(e=>e.messages.some(e=>{if(e.from!==`agent`)return!1;let t=Date.parse(e.at);return!Number.isNaN(t)&&t>n})).length}async function Wi(e,t,n){X(t,`syncing`);let r=await Hi(e,t,`sync`,n);return Vi(t,`sync`,`Syncing`,n),{...r,typed:[],command:!0}}async function Gi(e,t,n){if(t.state.status!==`reviewing`)throw new H(`this review is ${t.state.status}, so there is nothing to stop`);if(t.state.side!==`agent`)throw new H(`this review is already yours`);let r=await Hi(e,t,`stop`,n);return t.state.side=`you`,t.state.agent={act:null,activity:``,groups:null,lastPostAt:t.state.agent.lastPostAt},t.state.log.push({at:n,said:`stopped the agent`}),{...r,typed:[{event:`stopped`,detail:t.state.name,path:Ji(t)}]}}async function Ki(e,t,n){let r=await Hi(e,t,`done`,n);return t.state.side=`you`,t.state.agent={act:null,activity:``,groups:null,lastPostAt:n},r}async function qi(e,t,n){X(t,`following a merge`);let r=t.baseline;if(r===null)throw new H(`this review has no baseline`);let i=await e.relations.mergeOf(r);if(i===null)throw new H(`no commit on the base holds this change`);return t.state.selection=await nr(e.git,i),t.state.log.push({at:n,said:`followed the merge to ${i}`}),{...await Hi(e,t,`follow`,n),typed:[{event:`followed`,detail:i,path:Ji(t)}]}}function Ji(e){return`${e.slug}/${C}/baseline/baseline.json`}function Yi(e,t,n){if(X(e,`approving`),!vi(e))throw new H(`this review is not ready: every hunk is Seen and every thread closed first`);let r=e.baseline;if(r===null)throw new H(`this review has no baseline`);let i=t.name.trim();if(i===``)throw new H(`an approval carries the name that signed it`);let a=t.signature===null?null:Xi(t.signature);return e.approval={version:1,approved:!0,at:n,name:i,signature:a===null?null:ue,reason:``,loops:e.loops,fingerprint:r.fingerprint,commit:r.resolved.head,uncommitted:r.resolved.tree},e.state.status=`approved`,e.state.log.push({at:n,said:`approved by ${i}`}),{...Y([`approval`]),signature:a}}function Xi(e){let t=/^data:image\/png;base64,([A-Za-z0-9+/=]+)$/.exec(e.trim());if(t===null||t[1]===void 0)throw new H(`a signature is a PNG data URL drawn by the client`);return Buffer.from(t[1],`base64`)}function Zi(e,t,n){X(e,`closing without approval`);let r=t.trim();if(r===``)throw new H(`closing without approval carries a reason`);let i=e.baseline,a=hi(e);return e.approval={version:1,approved:!1,at:n,name:``,signature:null,reason:r,loops:e.loops,fingerprint:i?.fingerprint??``,commit:i?.resolved.head??``,uncommitted:i?.resolved.tree??!1},e.state.status=`closed`,e.state.side=`you`,e.state.agent={act:null,activity:``,groups:null,lastPostAt:e.state.agent.lastPostAt},e.state.log.push({at:n,said:`closed without approval with ${a.seen} of ${a.total} hunks Seen`}),Y([`approval`])}function Qi(e,t){let n=e=>String(e).padStart(2,`0`);return`${w}/${`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())}`}-${e}`}function $i(e,t){if(e.state.status!==`approved`&&e.state.status!==`closed`)throw new H(`a review is archived once it is approved or closed`);return e.state.status=`archived`,e.state.log.push({at:t,said:`archived`}),Y()}var ea=.8;function ta(e,t){let n=new Map,r=async t=>{let r=await na(e,t);if(r===null)return null;let i=`${r}\n${t.fingerprint}`,a=n.get(i);if(a!==void 0)return a;let o=await ia(e,t,r);return n.set(i,o),o};return{of:async n=>{let i=Pn(n.selection)?n.selection.head:null,a=await zn(e),o=await Bn(e),s=i===null?null:o.find(e=>e.name===i)??null;if(i!==null){let t=await ra(e,n,s?.tip??n.resolved.head);if(s===null||t){let e=await r(n);return e===null?t?{relation:`merged`,branch:i,mergedAs:null,why:`the base holds the branch`}:{relation:`history-rewritten`,branch:i,mergedAs:null,why:`the branch is gone and no commit on the base holds its change`}:{relation:`merged`,branch:i,mergedAs:e,why:`merged as ${e}`}}if(n.selection.kind===`branch`&&a!==i)return{relation:`different-branch`,branch:i,mergedAs:null,why:`${a??`no branch`} is checked out`}}if(n.selection.baseRef!==null&&await na(e,n)===null)return{relation:`history-rewritten`,branch:i,mergedAs:null,why:`${n.selection.baseRef} is gone`};let c=await Qn(e,n.selection).catch(()=>null);if(c===null)return{relation:`history-rewritten`,branch:i,mergedAs:null,why:`the selection no longer resolves`};if(c.rewritten)return{relation:`history-rewritten`,branch:i,mergedAs:null,why:`HEAD no longer descends from the head of this review`};if(i!==null&&!await Gn(e,n.resolved.head,c.head))return{relation:`history-rewritten`,branch:i,mergedAs:null,why:`${i} no longer holds the commits this review was of`};if(c.base!==n.resolved.base)return{relation:`out-of-sync`,branch:i,mergedAs:null,why:`the base moved`};if(c.head!==n.resolved.head)return{relation:`out-of-sync`,branch:i,mergedAs:null,why:`new commits`};let l=await sa(e,n,t.workspace);return l===null?{relation:`current`,branch:i,mergedAs:null,why:`the tree is the baseline`}:{relation:`out-of-sync`,branch:i,mergedAs:null,why:l}},mergeOf:r}}async function na(e,t){let n=t.selection.baseRef;return n===null?null:e.commit(n).catch(()=>null)}async function ra(e,t,n){let r=await na(e,t);return r!==null&&Gn(e,n,r)}async function ia(e,t,n){if(t.entries.length===0)return null;let r=t.resolved.base,i=(await e.text(`log-first-parent`,r,n).catch(()=>``)).split(`
|
|
18
|
+
`).filter(e=>e!==``).map(e=>e.split(` `)[0]??``).filter(e=>e!==``).slice(0,200),a=new Set(t.entries.map(e=>e.id)),o=t.entries.filter(e=>e.hunk!==null).length;for(let n of i){if(!aa(await e.text(`diff-tree`,n).catch(()=>``),o))continue;let r=await e.commit(`${n}^`).catch(()=>null);if(r===null)continue;let i=En(L(await e.bytes(`diff`,r,n,!1)));if(i.fingerprint===t.fingerprint||i.entries.filter(e=>a.has(e.id)).length/a.size>=.8)return n}return null}function aa(e,t){let n=0,r=0;for(let t of e.split(`
|
|
19
|
+
`)){if(t===``)continue;let e=t.split(` `);n+=oa(e[0])+oa(e[1]),r+=1}return r!==0&&n>=Math.floor(t*ea)}function oa(e){let t=Number(e);return Number.isFinite(t)?t:0}async function sa(e,t,n){if(t.tree===null)return null;if((await e.bytes(`status`)).toString(`utf8`)!==t.tree.porcelain)return`the working tree changed`;let r=b(n);for(let e of t.tree.files){let t=ca(r,e);if(t!==null)return t}return null}function ca(e,t){let n=b(e,t.path);if(!xt(e,n))return`${t.path} is not in the workspace`;let r;try{if(!xt(e,u(_(n))))return`${t.path} is not in the workspace`;r=i(n)}catch{return`${t.path} is gone`}let a=r.isSymbolicLink();if(!a&&!r.isFile())return`${t.path} is not a file any more`;try{let e=a?Buffer.byteLength(l(n)):r.size;if(e!==t.size)return`${t.path} was edited`;if(r.mtimeMs===t.mtimeMs)return null;if(e>pr.blobBytes)return`${t.path} is too large to check`;let i=a?Buffer.from(l(n),`utf8`):s(n);return S(`sha256`).update(i).digest(`hex`)===t.hash?null:`${t.path} was edited`}catch{return`${t.path} is gone`}}var la=[`stages`,`state`,`start`,`metadata`,`reply`,`activity`,`done`,`log`],ua=[`metadata`,`reply`,`activity`,`done`],da=[...ua,`log`];function fa(e,t){if(da.includes(t)){if(e.state.status!==`reviewing`)throw new H(`this review is ${e.state.status}, so it takes no more work`);if(ua.includes(t)&&e.state.side!==`agent`)throw new H(`this review awaits the reviewer, so there is nothing to post`)}}var pa=e=>typeof e==`object`&&!!e&&!Array.isArray(e);function ma(e,t){if(!pa(e))throw new H(`${t} is an object`);return e}var Z=(e,t=``)=>typeof e==`string`?e:t,ha=e=>Array.isArray(e)?e:[];function ga(e){let t=Z(ma(e,`this`).said).trim();if(t===``)throw new H("say something in `said`");return t}function _a(e){let t=ga(e),n=ma(e,`this`).groups;if(n==null)return{said:t,groups:null};if(typeof n!=`number`||!Number.isInteger(n)||n<0)throw new H("`groups` is how many groups there will be, as a whole count");return{said:t,groups:n}}function va(e){let t=ma(e,`a reply`),n=Z(t.thread).trim(),r=Z(t.text).trim();if(n===``)throw new H("a reply names the thread it is on in `thread`");if(r===``)throw new H("a reply carries its words in `text`");return{thread:n,text:r}}function ya(e){let t=ma(e,`metadata`),n=Z(t.fingerprint).trim();if(n===``)throw new H("metadata names the baseline it was written for in `fingerprint`");let r=[],i=new Set;for(let e of ha(t.groups)){let t=ma(e,`a group`),n=Z(t.id).trim();if(n===``)throw new H("a group names itself in `id`");if(n===`ungrouped`)throw new H(`${Me} is the tool's own group and is not posted`);if(i.has(n))throw new H(`two groups are called ${n}`);i.add(n),r.push({id:n,name:Z(t.name,n),narrative:Z(t.narrative),facts:ha(t.facts).filter(e=>typeof e==`string`),hunks:ha(t.hunks).filter(e=>typeof e==`string`)})}let a=[];for(let e of ha(t.notes)){let t=ma(e,`a note`),n=Z(t.hunk).trim();if(n===``)throw new H("a note names the hunk it is on in `hunk`");let r=Z(t.kind);if(!ke.includes(r))throw new H("a note is `info`, `attention` or `issue`");let i=Z(t.text).trim();if(i===``)throw new H("a note carries its words in `text`");let o=t.lines===void 0||t.lines===null?null:ha(t.lines).filter(e=>Number.isInteger(e));if(o!==null&&o.length===0)throw new H(`a note that names lines names at least one`);a.push({hunk:n,kind:r,lines:o,text:i,key:Ae(r,o,i)})}return{fingerprint:n,groups:r,notes:a}}function ba(e,t){let n=e.baseline;if(n===null)throw new H(`this review has no baseline to group`);if(t.fingerprint!==n.fingerprint)throw new H(`the baseline changed; the review awaits you`);let r=new Map(n.entries.map(e=>[e.id,e]));for(let e of t.groups)for(let t of e.hunks)if(!r.has(t))throw new H(`${e.id} names ${t}, which this baseline does not hold`);for(let e of t.notes){let t=r.get(e.hunk);if(t===void 0)throw new H(`a note names ${e.hunk}, which this baseline does not hold`);xa(n,t,e)}let i={version:1,fingerprint:n.fingerprint,groups:t.groups,notes:t.notes};return e.metadata=i,{ungrouped:yi(n,i),groups:t.groups.length,notes:t.notes.length}}function xa(e,t,n){if(n.lines===null)return;let r=t.hunk===null?null:e.files[t.file]?.hunks[t.hunk]??null;if(r===null)throw new H(`${n.hunk} changes no line, so a note on it names no lines`);let i=r.lines.map(e=>e.newLine).filter(e=>e!==null),a=i[0],o=i[i.length-1];if(a===void 0||o===void 0)throw new H(`${n.hunk} shows no new-side line, so a note on it names no lines`);for(let e of n.lines)if(e<a||e>o)throw new H(`a note names line ${e}, which is outside ${n.hunk}`)}function Sa(e,t,n){let r=e.threads.threads.find(e=>e.id===t.thread);if(r===void 0)throw new H(`there is no thread called ${t.thread}`);if(!r.open)throw new H(`${t.thread} is closed`);return Ei(e.threads,r,`agent`,t.text,n),{thread:r.id}}function Ca(e,t,n,r=null){e.state.agent.activity=t,r!==null&&(e.state.agent.groups=r),e.state.agent.lastPostAt=n}function wa(e,t,n){e.state.log.push({at:n,said:t}),e.state.side===`agent`&&(e.state.agent.lastPostAt=n)}var Ta=200,Ea=2e3,Da=e=>typeof e==`object`&&!!e&&!Array.isArray(e);function Q(e,t){if(!Da(e))throw new H(`${t} is an object`);return e}var $=(e,t=``)=>typeof e==`string`?e:t,Oa=e=>Array.isArray(e)?e:[],ka=(e,t=0)=>typeof e==`number`&&Number.isFinite(e)?e:t,Aa=e=>Oa(e).filter(e=>typeof e==`string`);function ja(e){if(e==null)return null;let t=Oa(e).map(e=>ka(e)).filter(e=>Number.isInteger(e)&&e>0);return t.length===0?null:t}function Ma(e){let t=$(e.hunk).trim();if(t===``)throw new H("name the hunk in `hunk`");return t}function Na(e){let t=Q(e,`a selection`),n=$(t.kind),r=[`branch`,`last-commit`,`commit`,`range`,`other-branch`];if(!r.includes(n))throw new H(`a selection is one of ${r.join(`, `)}`);let i={kind:n,uncommitted:t.uncommitted===!0};return typeof t.branch==`string`&&(i.branch=t.branch),typeof t.commit==`string`&&(i.commit=t.commit),typeof t.from==`string`&&(i.from=t.from),typeof t.to==`string`&&(i.to=t.to),typeof t.base==`string`&&(i.base=t.base),i}function Pa(e){let t=Q(e,`a review`);return{name:$(t.name).trim(),selection:Na(t.selection)}}function Fa(e){let t=Q(e,`the pending feedback`),n=[];for(let e of Oa(t.items)){let t=Q(e,`a pending item`),r=$(t.act);if(!Te.includes(r))throw new H(`an item is one of ${Te.join(`, `)}`);let i=typeof t.hunk==`string`?t.hunk:null,a=typeof t.group==`string`?t.group:null;if(i===null&&a===null)throw new H(`an item names a hunk or a group`);let o=$(t.text).trim();if(o===``&&r!==`undo`)throw new H("an item says something in `text`");let s=ja(t.lines);n.push({id:$(t.id),at:$(t.at),act:r,hunk:i,group:a,lines:s,text:o,label:null})}return n}function Ia(e){let t=gt(e.root),r=gt(e.workspace),i=e.clock??(()=>new Date),a=hn({workspace:r,exclude:[t]}),o=ta(a,{workspace:r}),s=e.onChange,c=s?Pt(t,s,{shared:ve,entries:`children`,coalesce:`per-entry`}):null,l=n=>({root:t,git:a,relations:o,workspace:r,limits:e.limits,at:n}),d=(e,n)=>La(t,e,Fr(n)),f=e=>La(t,e,`${C}/${ue}`),p=null,m=async()=>(p===null&&(p=await Ga(a)),p),h=e=>`${t}\n${G(e)}`,g,_=async()=>{if(g!==void 0)return g;if(!await a.ok(`rev-parse-git-dir`))return g=`This workspace is not a git repository.`,g;let e=(await a.text(`rev-parse-top`).catch(()=>``)).trim();return g=e!==``&&u(e)===u(r)?null:`This workspace is inside the repository at ${e}, not the top of it, so a review of it would be a review of the wrong paths.`,g},v=(e,n)=>(Mr(W(t,G(e))),ei(t,e,n)),y=(e,t)=>U(h(e),async()=>{let n=i().toISOString();return t(v(e,n),n)}),ee=[`marks`,`threads`,`pending`,`dismissals`],b=async(e,n)=>U(h(e),async()=>{let r=i().toISOString(),a=v(e,r),o=await n(a,r),s=a.repaired?[...new Set([...o.wrote,...ee])]:o.wrote;return si(t,a,s),{review:await S(a),typed:o.typed,command:o.command,line:o.line??null}}),x=async(e,n,r,a)=>U(h(e),async()=>{let o=i().toISOString(),s=v(e,o);fa(s,n);let c=await r(s,o);return si(t,s,a(c)),c}),S=async e=>{let n=i();return{slug:e.slug,state:e.state,baseline:e.baseline===null?null:Ka(e.baseline),marks:Ua(e.marks),threads:e.threads,pending:e.pending,dismissals:e.dismissals,metadata:e.metadata,ungrouped:yi(e.baseline,e.metadata),relation:e.baseline===null?null:await o.of(e.baseline),loops:e.loops,progress:hi(e),attention:_i(e),ready:vi(e),stale:e.state.side===`agent`&&Ze(e.state.agent.lastPostAt,n),approval:e.approval,place:li(t,e.slug),configuredName:await m(),error:Wa(e)}};return{root:t,workspace:r,async list(){let e=await _(),n=[],a=[];for(let e of Va(t)){let r=await U(h(e),()=>(Mr(W(t,G(e))),$a(t,e,o,i())));(Yr(e)?a:n).push(r)}let s=(e,t)=>e.slug.localeCompare(t.slug);return n.sort(s),a.sort((e,t)=>s(t,e)),{root:Ba(t,r),active:n,archived:a,awaitingYou:n.filter(e=>!e.missing&&e.status===`reviewing`&&e.side===`you`).length,any:n.length+a.length>0,repository:e===null,error:e}},async review(e){return y(e,e=>S(e))},hunks(e,n,r){return Qa(ei(t,e,i().toISOString()),n,r)},blobLines(e,t,n,r){return Za(d(e,t),t,n,r)},options:async e=>{if(e==null)return ir(a);try{return{options:[await ar(a,Na(e))],notOffered:null}}catch(e){throw e instanceof H?e:new H(e instanceof Error?e.message:`that is not a selection`)}},async start(n,o=`form`){let s=await _();if(s!==null)throw new H(s);let l=Pa(n);return U(`${t}\n`,async()=>{let n=await tr(a,l.selection),s=await vr(a,n,{workspace:r,limits:e.limits});if(s.record.entries.length===0)throw new H(`Nothing to review in this selection.`);let u=i().toISOString(),d=l.name||xe(n);Qr(t);let f=$r(t,d,ne),p=W(t,f),m=Di(s.record.fingerprint),h={slug:f,dir:p,state:rt(d,f,n,o,u),marks:m.marks,threads:m.threads,pending:m.pending,dismissals:m.dismissals,metadata:{version:1,fingerprint:s.record.fingerprint,groups:[],notes:[]},approval:null,baseline:s.record,loops:0,repaired:!1,broken:[]};return si(t,h,[`marks`,`threads`,`pending`,`dismissals`]),Ar(p,s),c?.refollow(),{slug:f,path:`${f}/README.md`,state:h.state,command:!0}})},async act(e,n,r){switch(n){case`mark`:return b(e,(e,t)=>{let n=Q(r,`a mark`);return ki(e,{hunk:Ma(n),seen:n.seen!==!1},t)});case`bulk`:return b(e,(e,t)=>{let n=Q(r,`a bulk act`),i=$(n.kind);if(i!==`file`&&i!==`group`)throw new H("a bulk act covers a `file` or a `group`");let a=$(n.id).trim();if(a===``)throw new H("a bulk act names what it covers in `id`");return Ai(e,{kind:i,id:a},t)});case`comment`:return b(e,(e,t)=>{let n=Q(r,`a comment`),i=$(n.kind),a=[`undo`,`explain`,`comment`,`fix`,`talk`];if(!a.includes(i))throw new H(`a comment is one of ${a.join(`, `)}`);let o=ja(n.lines);return Ni(e,{hunk:Ma(n),kind:i,text:$(n.text),lines:o},t)});case`dismiss`:return b(e,(e,t)=>{let n=Q(r,`a dismissal`),i=$(n.key).trim();if(i===``)throw new H("name the note in `key`");return Li(e,{hunk:Ma(n),key:i,on:n.on!==!1},t)});case`group-comment`:return b(e,(e,t)=>{let n=Q(r,`a group comment`),i=$(n.group).trim();if(i===``)throw new H("a group comment names its group in `group`");return Pi(e,{group:i,text:$(n.text)},t)});case`close-thread`:return b(e,(e,t)=>{let n=$(Q(r,`a thread`).thread).trim();if(n===``)throw new H("name the thread in `thread`");return Ri(e,n,t)});case`pending`:return b(e,(e,t)=>Ii(e,Fa(r),t));case`send`:return b(e,(e,t)=>Bi(l(t),e,t));case`sync`:return b(e,(e,t)=>Wi(l(t),e,t));case`stop`:return b(e,(e,t)=>Gi(l(t),e,t));case`follow`:return b(e,(e,t)=>qi(l(t),e,t));case`approve`:return b(e,(e,n)=>{let i=Q(r,`an approval`),a=typeof i.signature==`string`?i.signature:null,o=Yi(e,{name:$(i.name),signature:a},n);return o.signature!==null&&eo(t,e.slug,o.signature),o});case`close`:return b(e,(e,t)=>Zi(e,$(Q(r,`a closing`).reason),t));case`archive`:return U(h(e),async()=>{let n=i().toISOString(),r=v(e,n),a=r.state.status===`archived`&&!Yr(r.slug)?{wrote:[],typed:[],command:!1}:$i(r,n);si(t,r,r.repaired?[`marks`,`threads`,`pending`]:[]);let o=Qi(r.slug,i());return mi(t,r.slug,o),r.slug=o,r.dir=W(t,o),{review:await S(r),typed:a.typed,command:!1,line:null}});case`place`:return U(h(e),async()=>{let n=i().toISOString(),a=G(e);if(Yr(a))throw new H(`this review is filed away, so it keeps no reading place`);let o=Q(r,`a place`),s={version:1,scroll:ka(o.scroll),expanded:Aa(o.expanded),group:typeof o.group==`string`?o.group:null,drafts:Je(o.drafts),at:n};ui(t,a,s);let c=Aa(o.read);if(c.length===0)return{review:null,typed:[],command:!1,line:null};let l=v(a,n),u=zi(l,c,n),d=l.repaired?[...new Set([...u.wrote,...ee])]:u.wrote;return d.length>0&&si(t,l,d),{review:await S(l),typed:[],command:!1,line:null}});default:throw new H(`there is no act called ${n}`)}},stages:()=>({root:t,limits:{...pr,...e.limits},verbs:la,reviews:Va(t)}),async agentState(e){return y(e,e=>{let n=fi(t,e.slug);return{slug:e.slug,name:e.state.name,status:e.state.status,side:e.state.side,act:e.state.agent.act,activity:e.state.agent.activity,selection:xe(e.state.selection),filedBy:e.state.filedBy,loops:e.loops,baseline:e.baseline===null?null:Ya(e.baseline),metadata:e.metadata,ungrouped:yi(e.baseline,e.metadata),threads:e.threads.threads,send:n[n.length-1]??null,awaits:Xa(e)}})},metadata:(e,t)=>x(e,`metadata`,e=>ba(e,ya(t)),()=>[`metadata`]),reply:(e,t)=>x(e,`reply`,(e,n)=>{let r=Sa(e,va(t),n);return Ca(e,e.state.agent.activity||`Answering`,n),r},()=>[`threads`]),activity:(e,t)=>x(e,`activity`,(e,n)=>{let r=_a(t);return Ca(e,r.said,n,r.groups),{said:r.said}},()=>[]),done:e=>x(e,`done`,async(e,t)=>{let n=await Ki(l(t),e,t);return{fingerprint:e.baseline?.fingerprint??``,line:n.line??null,wrote:n.wrote}},e=>e.wrote).then(e=>({fingerprint:e.fingerprint,line:e.line})),log:(e,t)=>x(e,`log`,(e,n)=>{let r=ga(t);return wa(e,r,n),{said:r}},()=>[]),blob:d,signature:f,raw(e){let t=e.split(`/`),n=t.pop()??``;if(n===`signature.png`)return f(t.join(`/`));if(t.pop()===`blobs`)return d(t.join(`/`),n);throw new N(V,e)},toolPath(e){if(!ve(e))throw new N(V,e);let r=qr(t,e);if(!n(r))throw new ct(V,e);return r},file:e=>Et(V,t,e),close:()=>c?.close()}}function La(e,t,n){return Dt(V,e,`${G(t)}/${n}`,za)}var Ra=RegExp(`^${T}/${ge}/([0-9a-f]{40}|[0-9a-f]{64})$`);function za(e){let t=e.indexOf(`/${C}/`);if(t===-1)return!1;let n=e.slice(t+C.length+2);return n===`signature.png`||Ra.test(n)}function Ba(e,t){return e===t?`.`:`${e.startsWith(`${t}/`)?e.slice(t.length+1):e}/`}function Va(e){let t=[];for(let n of Ha(e)){if(n===`archive`){for(let r of Ha(Kr(e,n)))t.push(`archive/${r}`);continue}t.push(n)}return t.sort()}function Ha(e){try{return c(e,{withFileTypes:!0}).filter(e=>e.isDirectory()&&!e.name.startsWith(`.`)).map(e=>e.name)}catch{return[]}}function Ua(e){return{version:e.version,fingerprint:e.fingerprint,marks:e.marks.map(({hunk:e,at:t,act:n})=>({hunk:e,at:t,act:n})),acts:e.acts,changed:e.changed.map(({hunk:e,at:t})=>({hunk:e,at:t}))}}function Wa(e){if(e.baseline===null)return`${C}/${T}/baseline.json is not there to be read, so there is nothing left to review; closing this review without approval is what is left`;if(e.broken.length===0)return null;let t=e.broken.map(e=>e.replace(/\.json$/,`.broken.json`));return`${e.broken.join(` and `)} could not be read and started again; what was there is kept as ${t.join(` and `)}`}async function Ga(e){return(await e.text(`config-user-name`).catch(()=>``)).trim()}function Ka(e){let t=new Map;for(let n of e.entries)t.has(n.file)||t.set(n.file,n.fileKey);return{fingerprint:e.fingerprint,computedAt:e.computedAt,resolved:e.resolved,commits:e.commits,files:e.files.map((e,n)=>qa(e,t.get(n)??e.path)),entries:e.entries.map(t=>Ja(e,t)),totals:e.totals}}function qa(e,t){return{key:t,path:e.path,oldPath:e.oldPath,status:e.status,similarity:e.similarity,binary:e.binary,category:e.category,untracked:e.untracked,added:e.added,deleted:e.deleted,oldBlob:e.oldBlob,newBlob:e.newBlob,oldBytes:e.oldBytes,newBytes:e.newBytes}}function Ja(e,t){let n=e.files[t.file],r=t.hunk===null?null:n?.hunks[t.hunk]??null;return{id:t.id,file:t.file,header:r?.header??``}}function Ya(e){return{fingerprint:e.fingerprint,computedAt:e.computedAt,totals:e.totals,files:e.files.map((t,n)=>({path:t.path,oldPath:t.oldPath,hunks:e.entries.filter(e=>e.file===n).map(e=>({id:e.id,header:e.hunk===null?``:t.hunks[e.hunk]?.header??``}))}))}}function Xa(e){let t=e.state;if(t.status!==`reviewing`)return{side:t.side,act:null,reason:`this review is ${t.status}`};if(t.side===`you`)return{side:`you`,act:null,reason:`the reviewer has this review`};let n=t.agent.act===`prepare`?`group the baseline and write its narratives`:t.agent.act===`process`?`work through the newest send`:`group what is new and revise the narratives the new code made wrong`;return{side:`agent`,act:t.agent.act,reason:n}}function Za(e,t,n,r){let i=e.bytes.toString(`utf8`).split(`
|
|
20
|
+
`);i[i.length-1]===``&&i.pop();let a=Math.max(1,Math.trunc(n)),o=Math.min(Ea,Math.max(1,Math.trunc(r)));return{blob:t,from:a,total:i.length,lines:i.slice(a-1,a-1+o)}}function Qa(e,t,n){let r=e.baseline;if(r===null)throw new H(`this review has no baseline`);let i=Math.max(0,Math.trunc(t)),a=Math.min(200,Math.max(1,Math.trunc(n))),o=r.entries.slice(i,i+a),s=[];for(let e of o){let t=r.files[e.file];if(t===void 0)continue;let n=e.hunk===null?null:t.hunks[e.hunk]??null;s.push({id:e.id,file:e.file,path:t.path,oldPath:t.oldPath,status:t.status,binary:t.binary,untracked:t.untracked,oldBlob:t.oldBlob,newBlob:t.newBlob,header:n?.header??``,heading:n?.heading??``,oldStart:n?.oldStart??0,oldLines:n?.oldLines??0,newStart:n?.newStart??0,newLines:n?.newLines??0,lines:n?.lines??[],nonTextual:e.hunk===null,facts:e.facts})}return{from:i,count:s.length,total:r.entries.length,fingerprint:r.fingerprint,hunks:s}}async function $a(e,t,n,r){let i;try{i=ei(e,t,r.toISOString())}catch{return{slug:t,name:t.split(`/`).pop()??t,status:`reviewing`,side:`you`,filedBy:`form`,progress:{seen:0,total:0,left:0},relation:null,activity:``,lastPostAt:null,stale:!1,selection:``,branch:null,created:``,endedAt:null,approved:null,missing:!0}}let a=i.state,o=a.selection.kind===`branch`||a.selection.kind===`other-branch`?a.selection.head:null;return{slug:i.slug,name:a.name,status:a.status,side:a.side,filedBy:a.filedBy,progress:hi(i),relation:i.baseline===null||a.status!==`reviewing`?null:await n.of(i.baseline),activity:a.agent.activity,lastPostAt:a.agent.lastPostAt,stale:a.side===`agent`&&Ze(a.agent.lastPostAt,r),selection:xe(a.selection),branch:o,created:a.created,endedAt:i.approval?.at??null,approved:i.approval===null?null:i.approval.approved,missing:!1}}function eo(e,t,n){P(di(e,t),n)}export{Ea as LINES_MAX,Ta as PAGE_MAX,H as Refused,Ia as createReviewsModule,ut as statusFor};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{closeSync as e,constants as t,existsSync as n,fstatSync as r,lstatSync as i,mkdirSync as a,openSync as o,readFileSync as s,readdirSync as c,realpathSync as l,renameSync as u,rmSync as d,statSync as f,watch as p,writeFileSync as m}from"node:fs";import{basename as h,dirname as g,isAbsolute as _,join as v,relative as ee,resolve as te,sep as ne}from"node:path";import{createHash as re}from"node:crypto";var y=`.specs`,ie=`reader-state.json`,ae=`user-feedback.json`,oe=`pending-annotations.json`,se=`user-feedback-assets`;function ce(){return{version:1,units:{},dismissed:[]}}function le(e){return{version:1,entry:e,rounds:[]}}function b(e){return{version:1,entry:e,annotations:[]}}var x=e=>typeof e==`object`&&!!e&&!Array.isArray(e),S=(e,t=``)=>typeof e==`string`?e:t;function ue(e){let t;try{t=JSON.parse(e||`null`)}catch{return ce()}if(!x(t)||t.version!==1)return ce();let n=ce();if(x(t.units))for(let[e,r]of Object.entries(t.units)){if(!x(r))continue;let t={};typeof r.readHash==`string`&&(t.readHash=r.readHash),typeof r.readAt==`string`&&(t.readAt=r.readAt),n.units[e]=t}return Array.isArray(t.dismissed)&&(n.dismissed=t.dismissed.filter(e=>typeof e==`string`)),n}function de(e,t){let n;try{n=JSON.parse(e||`null`)}catch{return b(t)}if(!x(n)||n.version!==1)return b(t);let r=[];if(Array.isArray(n.annotations))for(let e of n.annotations)!x(e)||typeof e.id!=`string`||typeof e.unit!=`string`||e.id===``||e.unit===``||r.push({id:e.id,unit:e.unit,file:S(e.file),heading:S(e.heading),kind:e.kind===`remove`?`remove`:`comment`,quote:S(e.quote),text:S(e.text)});return{version:1,entry:S(n.entry,t),annotations:r}}function fe(e,t){let n;try{n=JSON.parse(e||`null`)}catch{return le(t)}if(!x(n)||n.version!==1)return le(t);let r=[];if(Array.isArray(n.rounds))for(let e of n.rounds){if(!x(e))continue;let t=[];if(Array.isArray(e.comments))for(let n of e.comments){if(!x(n)||typeof n.unit!=`string`)continue;let e=[];if(Array.isArray(n.assets))for(let t of n.assets)!x(t)||typeof t.path!=`string`||e.push({path:t.path,name:S(t.name,t.path),type:S(t.type)});t.push({unit:n.unit,file:S(n.file),heading:S(n.heading),kind:n.kind===`remove`?`remove`:`comment`,quote:S(n.quote),text:S(n.text),assets:e})}r.push({submittedAt:S(e.submittedAt),comments:t})}return{version:1,entry:S(n.entry,t),rounds:r}}function C(e){return e.toLowerCase().replace(/`/g,``).replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``)||``}var pe=`state.json`,w=[{id:`exploration`,title:`High-level exploration`,group:`discovery`,about:`We think the problem through together first - directions to take, risks, and what is still unclear.`},{id:`interview`,title:`Interview`,group:`discovery`,about:`I ask you focused questions until nothing important is left open.`},{id:`research`,title:`Research`,group:`discovery`,about:`I look outside your code - a library, a protocol, an algorithm, a subject area - and write up what I find.`},{id:`codebase-analysis`,title:`Codebase analysis`,group:`discovery`,about:`I read the parts of your code this work touches and note what shapes the design.`},{id:`technical-specs`,title:`Technical specs`,group:`deliverables`,about:`A written specification another agent can build from without asking you anything.`},{id:`ui-mocks`,title:`UI mocks`,group:`deliverables`,about:`Mock screens you open in your browser and comment on before anything is built.`},{id:`execution-plan`,title:`Execution plan`,group:`deliverables`,about:`The work split into phases, each with a goal and a way to tell it is done.`},{id:`quality-review`,title:`Quality review`,group:`deliverables`,about:`Fresh helper agents review everything we wrote, and I fix what is plainly wrong and bring the judgment calls to you.`}],me=[`exploration`,`ui-mocks`];function T(e){return w.find(t=>t.id===e)??null}var he=[{id:`per-phase`,said:`a commit per phase`},{id:`single`,said:`a single commit at the end`},{id:`none`,said:`no commits`}],ge=[{id:`current`,said:`the current branch`},{id:`new`,said:`a new branch`}],_e=[{id:`none`,said:`none`},{id:`chosen`,said:`after chosen phases`},{id:`every`,said:`every phase`}];function ve(e,t){return{version:1,name:e,created:t,status:`specifying`,protocol:[],modes:{imagination:!1},wish:{imagination:!1},stageSettings:{research:null},activity:{said:``,at:``},awaiting:[],phases:[],runRecommendations:null,runDecisions:null,reviews:[],approvals:[],log:[]}}var E=e=>typeof e==`object`&&!!e&&!Array.isArray(e),D=(e,t=``)=>typeof e==`string`?e:t,O=(e,t,n)=>t.includes(e)?e:n,ye=[`specifying`,`ready`,`executing`,`complete`],be=[`waiting`,`running`,`done`],xe=[`gate`,`round`,`protocol`],Se=[`focused`,`named`,`broad`],Ce=he.map(e=>e.id),we=ge.map(e=>e.id),Te=_e.map(e=>e.id);function Ee(e){if(!E(e)||e.scope===void 0)return null;let t=O(e.scope,Se,`focused`);return{scope:t,subject:t===`named`?k(D(e.subject)):``}}function k(e,t=200){return e.replace(/\p{C}+/gu,` `).replace(/\s+/g,` `).trim().slice(0,t)}function De(e){if(!E(e))return null;let t=[];for(let n of Array.isArray(e.checkpoints)?e.checkpoints:[]){if(!E(n))continue;let e=Array.isArray(n.panel)?n.panel.filter(e=>typeof e==`string`).map(e=>k(e)):[];t.push({after:C(D(n.after)),why:k(D(n.why)),panel:e,chosen:n.chosen!==!1&&e.length>0})}return{commits:O(e.commits,Ce,`per-phase`),branch:O(e.branch,we,`current`),branchName:k(D(e.branchName)),pauses:O(e.pauses,Te,`none`),pausePhases:Array.isArray(e.pausePhases)?e.pausePhases.filter(e=>typeof e==`string`).map(e=>C(e)):[],checkpoints:t}}function Oe(e){if(!E(e))return null;let t=De(e);if(t===null)return null;let n={};if(E(e.pauseReasons))for(let[t,r]of Object.entries(e.pauseReasons)){if(typeof r!=`string`)continue;let e=k(r);e!==``&&(n[C(t)]=e)}return{...t,pauseReasons:n,noPauseReason:k(D(e.noPauseReason))}}function ke(e,t=``,n=``){let r;try{r=JSON.parse(e||`null`)}catch{return ve(t,n)}if(!E(r)||r.version!==1)return ve(t,n);let i=ve(D(r.name,t),D(r.created,n)),a=D(r.status);if(ye.includes(a)&&(i.status=a),Array.isArray(r.protocol))for(let e of r.protocol){if(!E(e)||!T(D(e.id)))continue;let t=D(e.status);i.protocol.push({id:D(e.id),status:be.includes(t)?t:`waiting`,artifacts:Array.isArray(e.artifacts)?e.artifacts.filter(e=>typeof e==`string`):[]})}if(E(r.modes)&&(i.modes.imagination=r.modes.imagination===!0),E(r.wish)&&(i.wish.imagination=r.wish.imagination===!0),E(r.stageSettings)&&(i.stageSettings={research:Ee(r.stageSettings.research)}),E(r.activity)&&(i.activity={said:D(r.activity.said),at:D(r.activity.at)}),Array.isArray(r.awaiting))for(let e of r.awaiting){if(!E(e)||!e.id)continue;let t=D(e.kind);i.awaiting.push({id:D(e.id),kind:xe.includes(t)?t:`round`,title:D(e.title),file:D(e.file),payload:D(e.payload),declaredAt:D(e.declaredAt)})}if(Array.isArray(r.phases))for(let e of r.phases){if(!E(e)||!e.id)continue;let t=D(e.status);i.phases.push({id:D(e.id),title:D(e.title),status:be.includes(t)?t:`waiting`})}i.runRecommendations=Oe(r.runRecommendations);let o=De(r.runDecisions);if(o!==null&&E(r.runDecisions)&&(i.runDecisions={...o,decidedAt:D(r.runDecisions.decidedAt)}),Array.isArray(r.reviews))for(let e of r.reviews)!E(e)||typeof e.round!=`number`||i.reviews.push({round:e.round,verdict:D(e.verdict),findings:typeof e.findings==`number`?e.findings:0,judgments:typeof e.judgments==`number`?e.judgments:0,at:D(e.at)});if(Array.isArray(r.approvals))for(let e of r.approvals)!E(e)||!e.id||i.approvals.push({id:D(e.id),at:D(e.at),outcome:D(e.outcome)});if(Array.isArray(r.log))for(let e of r.log)E(e)&&i.log.push({at:D(e.at),said:D(e.said)});return i}function Ae(e,t){let n={};try{let t=JSON.parse(e||`null`);E(t)&&(n=t)}catch{n={}}return`${JSON.stringify({...n,...t},null,2)}\n`}function je(e){let t=e?.code;return typeof t==`string`&&Me.has(t)?t:null}var Me=new Set([`path-refused`,`no-entry`,`no-file`,`bad-request`,`too-large`,`upstream-failed`,`unreadable-answer`]),A=class extends Error{requested;code=`path-refused`;constructor(e,t){super(`${e}: refused path ${t}`),this.requested=t,this.name=`PathRefused`}},Ne=class extends Error{requested;code=`no-entry`;constructor(e,t){super(`${e}: no directory at ${t}`),this.requested=t,this.name=`NoSuchEntry`}},Pe=class extends Error{requested;code=`no-file`;constructor(e,t,n=`not a file`){super(`${e}: ${n} - ${t}`),this.requested=t,this.name=`NoSuchFile`}},Fe=class extends Error{requested;size;code=`too-large`;constructor(e,t,n){super(`${e}: too large to serve - ${t}`),this.requested=t,this.size=n,this.name=`FileTooLarge`}};function Ie(e){switch(je(e)){case`path-refused`:return 403;case`no-entry`:case`no-file`:return 404;case`bad-request`:return 400;case`too-large`:return 413;case`upstream-failed`:case`unreadable-answer`:return 502}return Le(e)?404:500}function Le(e){let t=e?.code;return t===`ENOENT`||t===`ENOTDIR`}var Re=32*1024*1024,ze=new Set([`md`,`markdown`,`mdown`,`mkd`]),Be=new Set([`html`,`htm`]),Ve=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`,`avif`,`bmp`,`ico`]),He=new Set(`txt text log json yaml yml toml ini cfg conf csv tsv xml css scss js jsx mjs cjs ts tsx py rb go rs java kt swift c h cpp hpp sh bash zsh fish sql graphql gql env diff patch lock gitignore editorconfig`.split(` `));function Ue(e){let t=e.slice(e.lastIndexOf(`/`)+1).slice(1).match(/\.([^.]+)$/);return t?t[1].toLowerCase():``}function We(e){return e.startsWith(`.`)}function Ge(e){let t=Ue(e);return ze.has(t)?`markdown`:Be.has(t)?`html`:Ve.has(t)?`image`:He.has(t)||!t?`text`:`binary`}var Ke=e=>/^[A-Z]/.test(e);function qe(e,t){let n=Ke(e);return n===Ke(t)?e.localeCompare(t,`en`):n?-1:1}function Je(e){let t=e,n=[];for(;;)try{return v(l(t),...n)}catch{let r=g(t);if(r===t)return e;n.unshift(h(t)),t=r}}function Ye(e){return Je(te(e))}function Xe(e){return e.split(`/`).some(e=>e!==``&&We(e))}function Ze(e,t,n,r){let i=n.replace(/^\/+/,``);if(_(n)||i.includes(`\0`))throw new A(e,n);let a=r===`require`;if(Xe(i)!==a)throw new A(e,n);let o=te(t,i);if(!et(t,o)||!et(t,Je(o))||Xe(ee(t,o).split(ne).join(`/`))!==a)throw new A(e,n);return o}function Qe(e,t,n){return Ze(e,t,n,`refuse`)}function $e(e,t,n){return Ze(e,t,n,`require`)}function et(e,t){return t===e||t.startsWith(e+ne)}function tt(e,t=`children`){if(t===`self`)return``;let n=e.split(`/`).filter(Boolean);return n.length<2?``:n[0]===`archive`?n.length>2?`archive/${n[1]}`:``:n[0]}var nt={md:`text/markdown; charset=utf-8`,markdown:`text/markdown; charset=utf-8`,html:`text/html; charset=utf-8`,htm:`text/html; charset=utf-8`,css:`text/css; charset=utf-8`,js:`text/javascript; charset=utf-8`,json:`application/json; charset=utf-8`,svg:`image/svg+xml`,png:`image/png`,jpg:`image/jpeg`,jpeg:`image/jpeg`,gif:`image/gif`,webp:`image/webp`,avif:`image/avif`,bmp:`image/bmp`,ico:`image/x-icon`,pdf:`application/pdf`,txt:`text/plain; charset=utf-8`};function rt(e){return nt[Ue(e)]??`application/octet-stream`}var it=Re;function at(e,t,n){return ot(e,Qe(e,t,n),n)}function ot(n,i,a){let c=o(i,t.O_RDONLY|t.O_NOFOLLOW);try{let e=r(c);if(!e.isFile())throw new Pe(n,a);if(e.size>it)throw new Fe(n,a,e.size);return{bytes:s(c),mediaType:rt(a),size:e.size,modified:new Date(e.mtimeMs).toISOString()}}finally{e(c)}}var st=`.tmp-`;function ct(e){return e.slice(e.lastIndexOf(`/`)+1).includes(st)}function j(e,t){a(g(e),{recursive:!0});let n=`${e}${st}${process.pid}-${Math.random().toString(36).slice(2)}`;try{m(n,t),u(n,e)}finally{d(n,{force:!0})}}function lt(e,t,n,r){j($e(e,t,n),r)}function ut(e,t,n){let r=$e(e,t,n);try{return s(r,`utf8`)}catch{return null}}function dt(e){try{let t=i(e);return{directory:t.isDirectory(),id:t.ino}}catch{return{directory:!1,id:0}}}function ft(e,t,r={}){let i=r.entries??`children`,a=r.coalesce??`per-path`,o=r.debounceMs??120,s=r.shared??(()=>!1),l=new Map,u=null,d=new Map,f=!1,m=t=>t===``?e:`${e}/${t}`,h=()=>{u=null;let e=[...l.values()];l.clear();for(let n of e)try{t(n)}catch{}},g=e=>{if(e===``||ct(e)||Xe(e)&&!s(e))return;let t=tt(e,i);if(a===`per-entry`)l.set(t,{entry:t,path:t,kind:`changed`});else{let r=n(m(e))?`changed`:`gone`;l.set(e,{entry:t,path:e,kind:r})}u||=setTimeout(h,o)},_=e=>{for(let[t,n]of d)(t===e||t.startsWith(`${e}/`))&&(n.watcher.close(),d.delete(t))},v=e=>{if(f||d.has(e))return;let t;try{t=p(m(e),(t,r)=>{if(!r)return;let i=r.toString();if(i===``)return;let a=e===``?i:`${e}/${i}`;if(i===e.split(`/`).at(-1)&&!n(m(a)))return;let o=d.get(a),s=dt(m(a));if(o&&s.directory){if(o.id===s.id)return;_(a),v(a),g(a);return}g(a),o?_(a):s.directory&&v(a)})}catch{return}t.on(`error`,()=>_(e)),d.set(e,{watcher:t,id:dt(m(e)).id});for(let t of ee(e))v(t)},ee=e=>{try{return c(m(e),{withFileTypes:!0}).filter(e=>e.isDirectory()).map(t=>e===``?t.name:`${e}/${t.name}`)}catch{return[]}};return v(``),{refollow(){f||v(``)},close(){f=!0,u&&clearTimeout(u),u=null;for(let e of d.values())e.watcher.close();d.clear()}}}var pt=`archive`;function mt(e){let t=e=>String(e).padStart(2,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}`}function ht(e,t){let n=e.split(`/`).pop()??e;return`${pt}/${mt(t)}-${n}`}var M=`specs`;function N(e,t){return Qe(M,e,t)}function P(e,t){return $e(M,e,t)}var F=`archive`;function gt(e){let t;try{t=c(e,{withFileTypes:!0})}catch{return[]}return t.filter(e=>!We(e.name)).sort((e,t)=>qe(e.name,t.name))}var _t=4*1024*1024;function vt(e,t,n){if(!(t===`markdown`||t===`text`)&&!(n>_t))try{return re(`sha1`).update(s(e)).digest(`hex`).slice(0,16)}catch{return}}function yt(e,t,n=!0,r=!1){let i=gt(e),a=[],o=0;for(let n of i){if(!n.isFile()&&!n.isDirectory()||n.isDirectory())continue;let i=t?`${t}/${n.name}`:n.name,s;try{s=f(v(e,n.name))}catch{continue}o=Math.max(o,s.mtimeMs);let c=Ge(n.name);a.push({path:i,name:n.name,dir:t,kind:c,size:s.size,modified:new Date(s.mtimeMs).toISOString(),hash:r?vt(v(e,n.name),c,s.size):void 0})}if(n)for(let n of i){if(!n.isDirectory())continue;let i=t?`${t}/${n.name}`:n.name,s=yt(v(e,n.name),i,!0,r);a.push(...s.files),o=Math.max(o,s.modified)}return{files:a,modified:o}}function bt(e,t,n){let r=t?v(e,t):e,i=yt(r,``,n),a=i.modified;if(!a)try{a=f(r).mtimeMs}catch{a=0}return{path:t,name:h(t||e),files:i.files.length,modified:new Date(a).toISOString(),archived:I(t),status:St(e,t),awaiting:Ct(e,t)}}function xt(e,t){if(!t)return null;try{return ke(s(v(e,t,y,pe),`utf8`),h(t))}catch{return null}}function St(e,t){return xt(e,t)?.status??null}function Ct(e,t){return xt(e,t)?.awaiting.length??0}function wt(e,t=`children`){let n=h(e);if(t===`self`)return{root:e,rootName:n,mode:t,entries:[bt(e,``,!0)]};let r=gt(e),i=[];for(let t of r)!t.isDirectory()||t.name===F||i.push(bt(e,t.name,!0));if(r.some(e=>e.isDirectory()&&e.name===F))for(let t of gt(v(e,F)).reverse())t.isDirectory()&&i.push(bt(e,`${F}/${t.name}`,!0));return{root:e,rootName:n,mode:t,entries:i}}function I(e){return e===F||e.startsWith(`${F}/`)}function Tt(e,t,n=`children`){let r=t?N(e,t):e,i;try{i=f(r)}catch{throw new Ne(M,t)}if(!i.isDirectory())throw new Ne(M,t);return{path:t,name:h(t||e),archived:I(t),files:yt(r,``,t!==``||n===`self`,!0).files}}function Et(e){let t=new Date(e);if(!/^\d{4}-\d{2}-\d{2}/.test(e)||Number.isNaN(t.getTime()))return``;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())}`}function Dt(e){let t=[`# ${e.name||`A piece of work`}`,``],n=Et(e.created);if(n&&t.push(`- Created: ${n}`),t.push(`- Status: ${e.status}`),e.modes.imagination&&t.push(`- Mode: imagination`),e.protocol.length>0){t.push(``,`## Protocol`,``);for(let n of e.protocol){let e=T(n.id),r=n.status===`running`?` (running)`:``;t.push(`- [${n.status===`done`?`x`:` `}] ${e?.title??n.id}${r}`)}}if(e.log.length>0){t.push(``,`## Log`,``);for(let n of e.log){let e=Et(n.at);t.push(e?`- ${e}: ${n.said}`:`- ${n.said}`)}}return`${t.join(`
|
|
2
|
+
`)}\n`}var Ot=e=>typeof e==`object`&&!!e&&!Array.isArray(e),L=(e,t=``)=>typeof e==`string`?e:t,kt=[`approved`,`changes`,`answered`];function At(e){if(!Ot(e))return null;let t=L(e.outcome);if(!kt.includes(t))return null;let n=[];for(let t of Array.isArray(e.questions)?e.questions:[])!Ot(t)||typeof t.question!=`string`||n.push({question:t.question,chosen:Array.isArray(t.chosen)?t.chosen.filter(e=>typeof e==`string`):[],said:L(t.said),answered:t.answered===!0});return{outcome:t,said:L(e.said),questions:n,accepted:e.accepted===!0,answeredAt:L(e.answeredAt)}}function R(e){return e?`${e}/${y}`:y}function z(e,t,n){lt(M,e,t,n)}function B(e,t){return ut(M,e,t)}function jt(e,t){return Nt(e,t),ue(B(e,`${R(t)}/${ie}`))}function Mt(e,t,n){V(e,t),z(e,`${R(t)}/${ie}`,`${JSON.stringify(n,null,2)}\n`)}function Nt(e,t){if(!n(t?N(e,t):e))throw new Pe(M,t,`no entry`)}function V(e,t){if(Nt(e,t),I(t))throw new A(M,t)}function Pt(e,t){return V(e,t),de(B(e,`${R(t)}/${oe}`),t).annotations}function Ft(e,t,n){V(e,t);let r={version:1,entry:t,annotations:n};z(e,`${R(t)}/${oe}`,`${JSON.stringify(r,null,2)}\n`)}function It(e,t){return`${e}-${t.replace(/[^A-Za-z0-9._-]+/g,`-`).replace(/^[-.]+/,``)||`attachment`}`}function Lt(e,t){if(!n(v(e,t)))return t;let r=t.lastIndexOf(`.`),i=r>0?t.slice(0,r):t,a=r>0?t.slice(r):``,o=2;for(;n(v(e,`${i}-${o}${a}`));)o++;return`${i}-${o}${a}`}function Rt(e,t){return fe(B(e,`${R(t)}/${ae}`),t).rounds}function zt(e,t,n,r=new Date){V(e,t);let i=R(t),o=`${i}/${se}`,s=P(e,o),c=r.toISOString().slice(0,19).replace(`T`,`-`).replace(/:/g,``),l=[];for(let t of n.comments){if(!t.unit)continue;let n=t.kind===`remove`?`remove`:`comment`;if(n===`comment`&&!t.text.trim()&&t.assets.length===0)continue;let r=[];for(let n of t.assets){a(s,{recursive:!0});let t=Lt(s,It(c,n.name));z(e,`${o}/${t}`,Buffer.from(n.data,`base64`)),r.push({path:`${se}/${t}`,name:n.name,type:n.type})}l.push({unit:t.unit,file:t.file,heading:t.heading,kind:n,quote:t.quote??``,text:t.text,assets:r})}let u=`${i}/${ae}`,d=fe(B(e,u),t);d.version=1,d.entry=t,d.rounds.push({submittedAt:r.toISOString(),comments:l}),z(e,u,`${JSON.stringify(d,null,2)}\n`);try{Bt(e,t,n.queued??[])}catch{}return{path:u,round:d.rounds.length}}function Bt(e,t,n){if(n.length===0)return;let r=new Set(n),i=Pt(e,t),a=i.filter(e=>!r.has(e.id));a.length!==i.length&&Ft(e,t,a)}var H=class extends Error{code=`bad-request`;constructor(e){super(`specs: ${e}`),this.name=`Refused`}},U=`rounds`,Vt=`intake.md`,Ht=`intake-assets`;function Ut(e){return`${R(e)}/${pe}`}function Wt(e,t){try{return s(P(e,t),`utf8`)}catch{return null}}function W(e,t,n=`children`){G(e,t,n);let r=Wt(e,Ut(t));return{state:ke(r,t===``?h(e):t.split(`/`).pop()??t),raw:r}}var Gt=e=>typeof e==`object`&&!!e&&!Array.isArray(e);function Kt(e,t,r){let i=r.trim();if(i===``)throw new H(`a decision card names the artifact it is about`);let a=N(e,t?`${t}/${i}`:i);if(!n(a)||!f(a).isFile())throw new H(`there is no ${i} in this piece of work`)}function G(e,t,n=`children`){let r=t.trim();if(!r&&n!==`self`)throw new H(`which piece of work? name one`);if(n!==`self`&&!qt(r))throw new H(`there is no piece of work called "${r}"`);let i=!1;try{i=f(r?N(e,r):e).isDirectory()}catch{i=!1}if(!i)throw new H(`there is no piece of work called "${r}"`)}function qt(e){let t=e.split(`/`);return t.some(e=>e===``)?!1:t.length===1?t[0]!==pt:t.length===2&&t[0]===`archive`}function K(e,t,n,r){if(I(t))throw new H(`${t} is signed off, so nothing is written into it`);z(e,Ut(t),Ae(r,n)),j(N(e,`${t}/README.md`),Dt(n))}function q(e,t,n){e.log.push({at:n,said:t})}function Jt(e){return e.replace(/[^A-Za-z0-9._-]+/g,`-`).replace(/^[-.]+/,``)||`attachment`}function Yt(e,t){let r=C(t)||`spec`;if(!n(N(e,r)))return r;let i=2;for(;n(N(e,`${r}-${i}`));)i++;return`${r}-${i}`}function Xt(e,t,n=new Date){let r=t.name.trim();if(!r)throw new H(`an intake needs a working name`);if(!t.text.trim()&&t.attachments.length===0)throw new H(`an intake needs something in it`);let i=Yt(e,r);a(N(e,i),{recursive:!0});let o=[];for(let n of t.attachments){let t=`${Ht}/${Jt(n.name)}`;a(N(e,`${i}/${Ht}`),{recursive:!0}),j(N(e,`${i}/${t}`),Buffer.from(n.data,`base64`)),o.push(t)}let s=[`# ${r}`,``,t.text.trim(),``];if(o.length>0){s.push(`## Attached`,``);for(let e of o)s.push(`- [${e.split(`/`).pop()}](${e})`);s.push(``)}j(N(e,`${i}/${Vt}`),s.join(`
|
|
3
|
+
`));let c=n.toISOString(),l=ke(null,r,c);return l.wish={imagination:t.wish.imagination===!0},q(l,`filed`,c),K(e,i,l,null),{entry:i,path:`${i}/${Vt}`}}var Zt=`${U}/protocol.json`;function Qt(e,t,n,r=new Date){G(e,t);let i=new Map;for(let e of n.stages){if(!T(e.id))throw new H(`no stage named ${e.id}`);i.set(e.id,e)}let a=w.map(e=>({id:e.id,recommended:i.get(e.id)?.recommended===!0,why:i.get(e.id)?.why??``})),o=r.toISOString();z(e,`${R(t)}/${Zt}`,`${JSON.stringify({stages:a,note:n.note,offeredAt:o},null,2)}\n`);let s={id:`protocol`,kind:`protocol`,title:`Confirm the steps for this work`,file:``,payload:Zt,declaredAt:o},{state:c,raw:l}=W(e,t);return c.awaiting=[...c.awaiting.filter(e=>e.id!==s.id),s],K(e,t,c,l),s}function $t(e,t,n,r=new Date){let i=new Set(n.stages);for(let e of i)if(!T(e))throw new H(`no stage named ${e}`);let{state:a,raw:o}=W(e,t),s=new Map(a.protocol.map(e=>[e.id,e])),c=a.approvals.some(e=>e.id===`protocol`),l={imagination:a.modes.imagination,settings:a.stageSettings},u=e=>i.has(e)||s.get(e)?.status===`done`||s.get(e)?.status===`running`;a.protocol=w.filter(e=>u(e.id)).map(e=>s.get(e.id)??{id:e.id,status:`waiting`,artifacts:[]});let d=new Set(a.protocol.map(e=>e.id)),f=n.imagination??l.imagination;a.modes.imagination=f&&a.protocol.some(e=>me.includes(e.id)),a.stageSettings={research:d.has(`research`)?n.settings.research??l.settings.research:null},a.awaiting=a.awaiting.filter(e=>e.kind!==`protocol`);let p={amended:c,added:[...d].filter(e=>!s.has(e)),removed:[...s.keys()].filter(e=>!d.has(e)),changed:!1,said:``};p.changed=p.added.length>0||p.removed.length>0||a.modes.imagination!==l.imagination||JSON.stringify(a.stageSettings)!==JSON.stringify(l.settings),p.said=en(p,d.size);let m=r.toISOString();return(!c||p.changed)&&(a.approvals.push({id:`protocol`,at:m,outcome:c?`amended`:`confirmed`}),q(a,c?`protocol amended - ${p.said}`:`protocol confirmed${a.modes.imagination?` - imagination mode`:``}`,m),n.note.trim()&&q(a,`said with the protocol: ${n.note.trim()}`,m)),K(e,t,a,o),{state:a,change:p}}function en(e,t){let n=e=>e.map(e=>T(e)?.title.toLowerCase()??e).join(`, `);if(!e.amended)return`${t} ${t===1?`step`:`steps`}`;let r=[];return e.added.length>0&&r.push(`added ${n(e.added)}`),e.removed.length>0&&r.push(`dropped ${n(e.removed)}`),r.length>0?r.join(`, `):e.changed?`the same steps, set up differently`:`the steps are as they were`}function tn(e,t,n){let{state:r,raw:i}=W(e,t);return r.runRecommendations=n,K(e,t,r,i),r}function nn(e,t,n,r=new Date){let{state:i,raw:a}=W(e,t),o=r.toISOString();return i.runDecisions={...n,decidedAt:o},q(i,`the run is set up - ${rn(i.runDecisions)}`,o),K(e,t,i,a),i}function rn(e){let t=he.find(t=>t.id===e.commits)?.said??e.commits,n=e.branch===`new`?`on ${e.branchName||`a new branch`}`:`here`,r=e.checkpoints.filter(e=>e.chosen).length;return`${t}, ${n}, ${r} review ${r===1?`checkpoint`:`checkpoints`}`}function an(e,t,n,r=new Date){let{state:i,raw:a}=W(e,t),o=r.toISOString();if(n.kind===`activity`)i.activity={said:n.said,at:o};else if(n.kind===`stage`){let e=T(n.stage);if(!e)throw new H(`no stage named ${n.stage}`);let t=i.protocol.find(e=>e.id===n.stage);if(!t)throw new H(`${n.stage} is not in this protocol`);t.status=n.status,n.artifacts&&(t.artifacts=[...new Set([...t.artifacts,...n.artifacts])]),n.status===`done`&&q(i,`${e.title.toLowerCase()} complete`,o),n.status===`running`&&(i.activity={said:e.title,at:o})}else if(n.kind===`phase`){let e=C(n.phase);if(!e)throw new H(`a phase needs a name`);let t=i.phases.find(t=>t.id===e),r=n.title??t?.title??n.phase;t?(t.status=n.status,t.title=r):i.phases.push({id:e,title:r,status:n.status}),n.status===`done`&&q(i,`${r} done`,o),n.status===`running`&&(i.activity={said:r,at:o})}else if(n.kind===`plan`){let e=new Set,t=[];for(let r of n.phases){let n=C(r.phase);if(!n||e.has(n))continue;e.add(n);let a=i.phases.find(e=>e.id===n);t.push({id:n,title:r.title||a?.title||r.phase,status:a?.status??`waiting`})}let r=i.phases.filter(t=>!e.has(t.id));i.phases=t,r.length>0&&q(i,`the plan no longer holds ${r.map(e=>e.title).join(`, `)}`,o)}else n.kind===`status`?(i.status=n.status,q(i,`status: ${n.status}`,o)):q(i,n.said,o);return K(e,t,i,a),i}function on(e,t,n,r=new Date){G(e,t);let i=C(n.id);if(!i)throw new H(`an awaiting item needs an id`);Gt(n.payload)&&n.payload.kind===`decision`&&Kt(e,t,n.file);let a=`${U}/${i}.json`,o=r.toISOString();z(e,`${R(t)}/${a}`,`${JSON.stringify({id:i,kind:n.kind,title:n.title,file:n.file,declaredAt:o,payload:n.payload},null,2)}\n`);let s={id:i,kind:n.kind,title:n.title,file:n.file,payload:a,declaredAt:o},{state:c,raw:l}=W(e,t);if(sn(s,n.payload))for(let n of c.awaiting)n.id===i||n.file!==s.file||sn(n,cn(e,t,n.id))&&fn(e,t,c,n,`superseded by ${i}`,o);return c.awaiting=[...c.awaiting.filter(e=>e.id!==i),s],K(e,t,c,l),s}function sn(e,t){return e.kind!==`gate`||!e.file?!1:!(Gt(t)&&t.kind===`decision`)}function cn(e,t,n){try{return J(e,t,n).payload}catch{return null}}function J(e,t,n){let r=C(n);if(!r)throw new H(`a round has an id`);let i=Wt(e,`${R(t)}/${U}/${r}.json`);if(i===null)throw new H(`no round named ${n}`);try{let e=JSON.parse(i);if(typeof e!=`object`||!e||Array.isArray(e))throw new H(`the round named ${n} could not be read`);return e}catch{throw new H(`the round named ${n} could not be read`)}}function ln(e,t,n){return J(e,t,n).answer??null}function un(e,t,n,r,i=new Date){let a=C(n),o=J(e,t,a);if(At(o.answer)!==null)throw new H(`${n} was already answered`);if(o.withdrawn!=null)throw new H(`${n} was withdrawn`);let s=i.toISOString(),c={...r,answeredAt:s},l=`${R(t)}/${U}/${a}.json`;z(e,l,`${JSON.stringify({...o,answer:c},null,2)}\n`);let{state:u,raw:d}=W(e,t),f=u.awaiting.find(e=>e.id===a);return u.awaiting=u.awaiting.filter(e=>e.id!==a),u.approvals.push({id:a,at:s,outcome:r.outcome}),q(u,`${f?.title||a}: ${pn[r.outcome]}`,s),K(e,t,u,d),{path:l,outcome:r.outcome}}function dn(e,t,n,r=new Date){let i=C(n.id);if(!i)throw new H(`a withdrawal names the ask it takes back`);let a=n.reason.trim();if(!a)throw new H(`a withdrawal says why the ask is no longer open`);let{state:o,raw:s}=W(e,t),c=o.awaiting.find(e=>e.id===i);if(!c)throw new H(`${n.id} is not waiting for an answer`);return fn(e,t,o,c,a,r.toISOString()),K(e,t,o,s),{path:`${R(t)}/${U}/${i}.json`,id:i}}function fn(e,t,n,r,i,a){let o=`${R(t)}/${U}/${r.id}.json`,s=null;try{s=J(e,t,r.id)}catch{s=null}if(s!==null){let t={...s,withdrawn:{at:a,reason:i}};z(e,o,`${JSON.stringify(t,null,2)}\n`)}n.awaiting=n.awaiting.filter(e=>e.id!==r.id),q(n,`${r.title||r.id}: withdrawn - ${i}`,a)}var pn={approved:`approved`,changes:`changes asked for`,answered:`answered`};function mn(e,t,n,r=new Date){let i=r.toISOString(),{state:a,raw:o}=W(e,t),s={...n,at:i};return a.reviews=[...a.reviews.filter(e=>e.round!==s.round),s].sort((e,t)=>e.round-t.round),q(a,`review round ${s.round}: ${s.verdict}`,i),K(e,t,a,o),a}var hn=`spec/SPEC.md`;function gn(e){try{return{at:e,before:s(e,`utf8`)}}catch{return{at:e,before:null}}}function _n(e){for(let t of e)t.before===null?d(t.at,{force:!0}):j(t.at,t.before)}function vn(e,t){if(/^Completed:/m.test(e))return null;let n=e.split(`
|
|
4
|
+
`),r=n.findIndex(e=>e.startsWith(`# `));return r===-1?`Completed: ${t}\n\n${e}`:(n.splice(r+1,0,``,`Completed: ${t}`),n.join(`
|
|
5
|
+
`))}function yn(e,t,r=`children`,i=new Date){if(r===`self`)throw new H(`this pane serves one piece of work, so there is no root to file it under`);let o=t.trim();if(!o)throw new H(`which piece of work? name one`);if(I(o))throw new H(`this piece of work is already archived`);let s=!1;try{s=f(N(e,o)).isDirectory()}catch{s=!1}if(!s)throw new H(`there is no piece of work called "${o}"`);let c=mt(i),l=ht(o,i),d=N(e,l);if(n(d))throw new H(`${l} is already there`);let{state:p,raw:m}=W(e,o,r),h=gn(N(e,`${o}/${hn}`)),_=[gn(N(e,`${o}/README.md`)),h,gn(P(e,`${o}/${y}/${pe}`))];try{if(p.status=`complete`,p.log.push({at:i.toISOString(),said:`signed off and archived`}),K(e,o,p,m),h.before!==null){let e=vn(h.before,c);e!==null&&j(h.at,e)}a(g(d),{recursive:!0}),u(N(e,o),d)}catch(e){throw _n(_),e instanceof H?e:new H(`it could not be filed away: ${e.message}`)}return{entry:l,path:`${l}/README.md`}}var Y=class extends Error{code=`bad-request`;constructor(e){super(`specs: ${e}`),this.name=`BadRequest`}},bn=new Set([Vt,`README.md`]);function xn(e,t){let n=t.split(`/`),r=n.pop()??``;return n.length===1&&n[0]&&bn.has(r)?N(e,t):P(e,t)}var X=(e,t)=>{if(typeof e!=`object`||!e||Array.isArray(e))throw new Y(`${t} is an object`);return e},Z=(e,t=``)=>typeof e==`string`?e:t,Q=e=>Array.isArray(e)?e:[],Sn=e=>typeof e==`object`&&!!e&&!Array.isArray(e);function Cn(e){let t=X(e,`an intake`),n=[];for(let e of Q(t.attachments)){let t=X(e,`an attachment`);if(typeof t.data!=`string`||typeof t.name!=`string`)throw new Y(`an attachment carries a name and base64 data`);n.push({name:t.name,type:Z(t.type),data:t.data})}return{name:Z(t.name),text:Z(t.text),attachments:n,wish:wn(t.wish)}}function wn(e){return{imagination:(typeof e==`object`&&e?e:{}).imagination===!0}}function Tn(e){let t=X(e,`a proposal`),n=[];for(let e of Q(t.stages)){let t=X(e,`a proposed stage`);if(typeof t.id!=`string`)throw new Y(`a proposed stage names one`);n.push({id:t.id,recommended:t.recommended===!0,why:Z(t.why)})}return{stages:n,note:Z(t.note)}}function En(e){let t=X(e,`a confirmation`),n=t.settings===void 0?{}:X(t.settings,`the settings`);return{stages:Q(t.stages).filter(e=>typeof e==`string`),imagination:t.imagination===void 0||t.imagination===null?null:t.imagination===!0,note:Z(t.note),settings:{research:Ee(n.research)}}}function Dn(e){let t=X(e,`a post`),n=Z(t.kind);if(n===`activity`||n===`note`)return{kind:n,said:Z(t.said)};if(n===`status`){let e=Z(t.status);if(!In.includes(e))throw new Y(`a status is one of ${In.join(`, `)}`);return{kind:n,status:e}}if(n===`phase`){let e=Z(t.status);if(!$.includes(e))throw new Y(`a phase status is one of ${$.join(`, `)}`);let r=Z(t.title);return{kind:n,phase:Z(t.phase),status:e,...r?{title:r}:{}}}if(n===`plan`){let e=Q(t.phases).filter(e=>typeof e==`object`&&!!e).map(e=>({phase:Z(e.phase),title:Z(e.title)})).filter(e=>e.phase!==``);if(e.length===0)throw new Y(`a plan post names at least one phase`);return{kind:n,phases:e}}if(n===`stage`){let e=Z(t.status);if(!$.includes(e))throw new Y(`a stage status is one of ${$.join(`, `)}`);let r=Q(t.artifacts).filter(e=>typeof e==`string`);return{kind:n,stage:Z(t.stage),status:e,artifacts:r}}throw new Y(`a post is an activity, a stage, a phase, a status or a note`)}function On(e){let t=X(e,`an answer`),n=Z(t.outcome);if(!An.includes(n))throw new Y(`an outcome is one of ${An.join(`, `)}`);let r=[];for(let e of Q(t.questions)){let t=X(e,`an answered question`);if(typeof t.question!=`string`)throw new Y(`an answer names its question`);let n=Q(t.chosen).filter(e=>typeof e==`string`),i=Z(t.said);r.push({question:t.question,chosen:n,said:i,answered:t.answered===!0})}return{outcome:n,said:Z(t.said),questions:r,accepted:t.accepted===!0,answeredAt:``}}function kn(e){let t=X(e,`a review round`);if(typeof t.round!=`number`)throw new Y(`a review round is numbered`);return{round:t.round,verdict:Z(t.verdict),findings:typeof t.findings==`number`?t.findings:0,judgments:typeof t.judgments==`number`?t.judgments:0,at:``}}var An=[`approved`,`changes`,`answered`];function jn(e){let t=De(X(e,`a run setup`));if(t===null)throw new Y(`a run setup is an object`);return t}function Mn(e){let t=Oe(X(e,`a run setup`));if(t===null)throw new Y(`a run setup is an object`);return t}function Nn(e){let t=X(e,`a withdrawal`);return{id:Z(t.id),reason:Z(t.reason)}}function Pn(e){let t=X(e,`a declaration`),n=Z(t.kind);if(n!==`gate`&&n!==`round`)throw new Y(`a declaration is a gate or a round`);let r={id:Z(t.id),kind:n,title:Z(t.title),file:Z(t.file),payload:t.payload??null};return Fn(r),r}function Fn(e){let t=e.payload;if(!Sn(t)||t.kind!==`decision`)return;if(e.file===``)throw new Y("a decision card names the artifact it is about in `file`");if(Z(t.heading)===``)throw new Y("a decision card names the section it is about in `heading`");let n=Array.isArray(t.questions)?t.questions:[];if(n.length!==1)throw new Y("a decision card asks exactly one question in `questions`");let r=n[0];if((Sn(r)&&Array.isArray(r.options)?r.options:[]).length<2)throw new Y(`a decision card offers two options at least`)}var In=[`specifying`,`ready`,`executing`,`complete`],$=[`waiting`,`running`,`done`],Ln=[ae,oe];function Rn(e){return Ln.some(t=>e.endsWith(`/${y}/${t}`))}function zn(e){let t=Ye(e.root),r=e.entries??`children`,i=e.onChange,a=i?ft(t,i,{shared:Rn,entries:r,coalesce:`per-path`}):null;return{root:t,dashboard:()=>wt(t,r),entry:e=>Tt(t,e,r),state:e=>jt(t,e),writeState(e,n){Mt(t,e,ue(typeof n==`string`?n:JSON.stringify(n)))},pending:e=>({...b(e),annotations:Pt(t,e)}),writePending(e,n){Ft(t,e,de(typeof n==`string`?n:JSON.stringify(n),e).annotations)},feedback(e,n){let r=n,i=r?.comments;if(!Array.isArray(i))throw new Y(`a submission is a list of comments`);let a=Q(r?.queued).filter(e=>typeof e==`string`);return zt(t,e,{comments:i,queued:a})},filed:e=>Rt(t,e),toolPath(e){let r=xn(t,e);if(!n(r))throw new Pe(M,e);return r},stages:()=>w,specState:e=>W(t,e,r).state,archive:e=>yn(t,e,r),intake:e=>Xt(t,Cn(e)),propose:(e,n)=>Qt(t,e,Tn(n)),confirm:(e,n)=>$t(t,e,En(n)),recommend:(e,n)=>tn(t,e,Mn(n)),decide:(e,n)=>nn(t,e,jn(n)),post:(e,n)=>an(t,e,Dn(n)),declare:(e,n)=>on(t,e,Pn(n)),withdraw:(e,n)=>dn(t,e,Nn(n)),answers:(e,n)=>ln(t,e,n),answer:(e,n,r)=>un(t,e,n,On(r)),review:(e,n)=>mn(t,e,kn(n)),round:(e,n)=>J(t,e,n),file:e=>at(M,t,e),close:()=>a?.close()}}export{Y as BadRequest,zn as createSpecsModule,Ie as statusFor};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: chamba-statusline
|
|
3
|
-
description: Explain where a session's status lives in chamba - the strip in the web interface, the snapshot behind it
|
|
3
|
+
description: Explain where a session's status lives in chamba - the strip in the web interface, and the snapshot behind it. Use when the user mentions the status line, asks why the terminal has none, asks what the strip above the composer means, or wants a status line of their own.
|
|
4
|
+
metadata:
|
|
5
|
+
audience: claude
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# chamba-statusline: Where a session's status is
|
|
@@ -25,31 +27,17 @@ The web interface shows the attached session's status in one line between the te
|
|
|
25
27
|
|
|
26
28
|
The strip belongs to the session it is drawn for, and only a claude session has one - the snapshot is a Claude Code feature, so a codex or opencode tab has no strip at all.
|
|
27
29
|
|
|
28
|
-
## Step 2 - The snapshot behind it
|
|
30
|
+
## Step 2 - The snapshot behind it
|
|
29
31
|
|
|
30
32
|
The script at `{{statusline_path}}` is what makes any of this exist. Claude Code runs it on every prompt render and hands it the session's state on stdin; the script parses it, resolves the pid of the claude process it was run by, and writes a small JSON file. Fields: `session_id`, `claude_pid`, `claude_pid_start`, `updated_at`, `context_tokens`, `context_used_pct`, `context_window_size`, `model`, `effort`, `quota_left_pct`, `quota_resets_at`, `quota_week_left_pct`, `quota_week_resets_at`, `version`. The two `quota_*` pairs are the five-hour and seven-day rate-limit windows; both percentages are what is LEFT, inverted from the percentage used that Claude Code reports.
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
- The web interface, which matches a snapshot to a session by that pid and draws the strip from it.
|
|
34
|
-
- The `context-usage` command, which is how an agent inspects its own context and quota from the terminal. Run it rather than reading the files by hand.
|
|
35
|
-
|
|
36
|
-
If the user wants the numbers without the browser, `context-usage` is the answer. It prints one labelled line per thing the snapshot carried:
|
|
37
|
-
|
|
38
|
-
```
|
|
39
|
-
session: 78b4025b-... (this session, updated 3s ago)
|
|
40
|
-
context: 70.8k tokens (7% of 1M window)
|
|
41
|
-
quota: 84% remaining, resets in 21m
|
|
42
|
-
weekly: 59% remaining, resets in 4d 6h
|
|
43
|
-
model: Fable 5 (effort high)
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
`quota` is the five-hour window and `weekly` the seven-day one; a window the account does not have prints no line at all, and neither does a field the snapshot is missing. The `(this session, ...)` marker means the snapshot was matched to the asking session by pid and is certainly its own; without it the newest file was used instead, and a `warning:` line says why that may mislead. The numbers are as of the moment the current prompt was submitted, so the turn in flight is not in them yet.
|
|
34
|
+
The web interface reads those files: it matches a snapshot to a session by that pid and draws the strip from it. The numbers are as of the moment the current prompt was submitted, so the turn in flight is not in them yet.
|
|
47
35
|
|
|
48
36
|
## Step 3 - When the user wants a status line of their own
|
|
49
37
|
|
|
50
38
|
The chamba script prints nothing on purpose: a status line is redrawn inside the conversation, so in a browser it scrolls away with the output and costs a row of the terminal every prompt. The strip is the same information somewhere it stays put.
|
|
51
39
|
|
|
52
|
-
A user who works in the terminal and wants a visible line back can have one - by pointing Claude Code at their own script. Explain the trade first (a custom script replaces chamba's, and chamba's is what writes the snapshots the strip
|
|
40
|
+
A user who works in the terminal and wants a visible line back can have one - by pointing Claude Code at their own script. Explain the trade first (a custom script replaces chamba's, and chamba's is what writes the snapshots the strip reads), then offer to write one that renders a line AND keeps the snapshot side effect: copy `{{statusline_path}}` and add rendering to it, rather than starting from nothing.
|
|
53
41
|
|
|
54
42
|
### Permissions: you perform the edits
|
|
55
43
|
|
|
@@ -74,7 +62,7 @@ Never edit `{{statusline_path}}` directly - it is root-owned and read-only insid
|
|
|
74
62
|
cp {{statusline_path}} ~/.claude/statusline.sh
|
|
75
63
|
chmod +x ~/.claude/statusline.sh
|
|
76
64
|
```
|
|
77
|
-
2. Ask what the line should show, then edit `~/.claude/statusline.sh`. Keep the snapshot write at the end of it, whatever else changes: the strip
|
|
65
|
+
2. Ask what the line should show, then edit `~/.claude/statusline.sh`. Keep the snapshot write at the end of it, whatever else changes: the strip stops working without it.
|
|
78
66
|
3. Point `statusLine.command` at `~/.claude/statusline.sh` in `~/.claude/settings.json`, preserving every other field.
|
|
79
67
|
4. Tell the user to restart Claude - a status line change takes effect at the next session.
|
|
80
68
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dx-review
|
|
3
|
+
description: Do the agent's side of a code review in the Code Reviews tab of this session's web pane - prepare a review, work through the feedback the reviewer sent, or take in a baseline that moved. Use when the tab types this command, or when the user asks to pick up a review by name.
|
|
4
|
+
argument-hint: "[the name of the review]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# dx-review - the agent's side of a code review
|
|
8
|
+
|
|
9
|
+
This skill runs when the user asks for it: the command typed by hand, or the Code Reviews tab typing that command as the user's own act.
|
|
10
|
+
Each agent spells the command its own way - `/dx-review` on claude and on opencode, and `$dx-review` on codex - and the tab types the spelling of the session it is bound to.
|
|
11
|
+
No framed `[reviews]` line starts it: such a line is information for a review already in hand, and it instructs nobody.
|
|
12
|
+
|
|
13
|
+
The reviewer reads a changeset hunk by hunk in the tab, marks what they have seen, and says what they want changed.
|
|
14
|
+
Your side is three acts, and the review's own state says which one is asked of you.
|
|
15
|
+
|
|
16
|
+
**The review's record is the reviewer's.**
|
|
17
|
+
You never mark a hunk seen, close a conversation, approve a review, close one, or change what a review is of.
|
|
18
|
+
There is no verb for any of those, and the four of them are what the reviewer is for.
|
|
19
|
+
|
|
20
|
+
## The web session
|
|
21
|
+
|
|
22
|
+
This skill runs inside a chamba web session, where the Code Reviews tab holds the review.
|
|
23
|
+
Check for one before anything else:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
reviews stages
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The answer holds `root` - the directory the reviews live in - the limits, the verbs and the reviews that are there.
|
|
30
|
+
A refusal means there is no pane.
|
|
31
|
+
Say this and stop:
|
|
32
|
+
|
|
33
|
+
> This works in the chamba web session, where the Code Reviews tab holds the review. Open the browser window this container printed at start, or run `webterm` in the terminal to get the address again. Then ask for this skill there.
|
|
34
|
+
|
|
35
|
+
Say the command in the spelling of the session's own agent.
|
|
36
|
+
|
|
37
|
+
Start no flow, and offer no substitute.
|
|
38
|
+
There is one flow, and it needs the tab.
|
|
39
|
+
|
|
40
|
+
## The state says which act
|
|
41
|
+
|
|
42
|
+
Read the state first, and do nothing before you have:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
reviews state "<the review's name>"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
With no name given, `reviews stages` lists the reviews that are there.
|
|
49
|
+
One of them is the review the tab woke you for: the one whose `awaits.side` is `agent`.
|
|
50
|
+
Where more than one is, say which ones and ask the reviewer in this terminal which they mean.
|
|
51
|
+
|
|
52
|
+
The answer holds what you need and nothing you have to work out:
|
|
53
|
+
|
|
54
|
+
| Field | What it is |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| `awaits` | `{ side, act, reason }` - who holds the review, which act is asked, and why, in one line |
|
|
57
|
+
| `act` | `prepare`, `process`, `sync`, or null |
|
|
58
|
+
| `side` | `agent` while the review is yours, `you` while it is the reviewer's |
|
|
59
|
+
| `status` | `reviewing` while there is work; `approved`, `closed` or `archived` where there is none |
|
|
60
|
+
| `baseline` | The changeset: the `fingerprint`, the totals, and every file with the id and header of each of its hunks |
|
|
61
|
+
| `metadata` | The grouping and the notes as they stand, and empty where nothing is grouped |
|
|
62
|
+
| `ungrouped` | The hunks no group holds, which is what a grouping post answers with |
|
|
63
|
+
| `threads` | Every conversation, with its anchor, whether it is open, and its messages |
|
|
64
|
+
| `send` | The newest batch the reviewer sent: `sentAt`, the `fingerprint` it was written against, and its `items` |
|
|
65
|
+
| `selection` | What the review is of, in one line |
|
|
66
|
+
| `loops` | How many times the reviewer has sent feedback |
|
|
67
|
+
|
|
68
|
+
Then act on `awaits`:
|
|
69
|
+
|
|
70
|
+
- **`side` is `you`** - the review is not yours. Every verb that writes is refused, and rightly. Say the review is with the reviewer and stop.
|
|
71
|
+
- **`status` is not `reviewing`** - the review is finished. Say so and stop.
|
|
72
|
+
- **`act` is one of the three** - do that act. `references/acts.md` holds each one in detail; read the one you are doing.
|
|
73
|
+
- **`act` is null and `side` is `agent`** - there is nothing waiting. Say so in this terminal and post nothing at all, `activity` and `done` included.
|
|
74
|
+
|
|
75
|
+
The last two cases are real cases, not faults.
|
|
76
|
+
The tab types this command for every act that hands a review over, and "Ask the agent to continue" types it again on a review that may be in hand already, so the command arriving is not by itself work to do.
|
|
77
|
+
A review that came back to the reviewer a moment ago answers `side: you`, and there is nothing for you in it.
|
|
78
|
+
|
|
79
|
+
### The three acts, in one line each
|
|
80
|
+
|
|
81
|
+
- **`prepare`** - the review has a baseline and no grouping. Group every hunk into a few pieces of work, give each group a narrative, and write the notes: `info` where an explanation helps the reviewer, `attention` where a passage needs a human eye, `issue` where you are certain something is wrong.
|
|
82
|
+
- **`process`** - the reviewer sent a batch. Do what each item asks, and reply in the conversation each item opened.
|
|
83
|
+
- **`sync`** - the baseline moved, because the reviewer synced the review, stopped you, or followed a merge. Group what is new, and revise what the new code made wrong.
|
|
84
|
+
|
|
85
|
+
## What you post
|
|
86
|
+
|
|
87
|
+
Five verbs, and they are the whole of what you may do to a review:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
echo '<json>' | reviews metadata "<review>" the grouping and the notes for this baseline
|
|
91
|
+
echo '<json>' | reviews reply "<review>" one reply in one conversation: { thread, text }
|
|
92
|
+
echo '<json>' | reviews activity "<review>" what you are doing right now: { said, groups? }
|
|
93
|
+
echo '<json>' | reviews log "<review>" one dated line for the activity log: { said }
|
|
94
|
+
reviews done "<review>" your act is finished
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
A payload is JSON on stdin, and the answer is JSON on stdout.
|
|
98
|
+
`references/acts.md` holds the shape of each payload.
|
|
99
|
+
|
|
100
|
+
**Post `activity` as you go.**
|
|
101
|
+
It is one short sentence in the present tense - "Grouping the parser changes", "Working on the second item" - and the tab shows it with the time you posted it.
|
|
102
|
+
A review that has said nothing for ten minutes is drawn as stale, so a long act posts as it moves rather than once at the end.
|
|
103
|
+
|
|
104
|
+
**Post `done` last, and only when the act is finished.**
|
|
105
|
+
It hands the review back to the reviewer, and the tool recomputes the baseline as it does.
|
|
106
|
+
So a `metadata` or a `reply` after `done` is refused: the review is no longer yours.
|
|
107
|
+
|
|
108
|
+
**Change no code that the act did not ask for.**
|
|
109
|
+
`done` recomputes the baseline from the tree as it stands, so any edit of yours becomes part of what the reviewer reads, and the marks they made are carried onto it.
|
|
110
|
+
`prepare` and `sync` are reading acts: group it, note it, reply, and leave the code alone.
|
|
111
|
+
`process` is the one act that writes code, and it writes what the reviewer asked for and no more.
|
|
112
|
+
|
|
113
|
+
**A grouping is posted against the baseline you read.**
|
|
114
|
+
The post carries that baseline's `fingerprint`, and a post against a fingerprint that has moved on is refused with the reason.
|
|
115
|
+
That is not an error to work around: the reviewer changed what the review is of while you worked, the review awaits you again, and the answer is to read the state and work from the baseline that is there now.
|
|
116
|
+
|
|
117
|
+
## When you are not sure
|
|
118
|
+
|
|
119
|
+
Ask the reviewer, in this terminal, and wait for the answer.
|
|
120
|
+
A piece of feedback that could mean two things is worth one question; a guess costs the reviewer a whole loop of the review.
|
|
121
|
+
|
|
122
|
+
The one thing never to do with an unclear item is to reply in its conversation as though it were settled.
|
|
123
|
+
A reply is your answer to what was asked, and the tab shows it as one.
|