alchemylab 3.0.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +9 -5
- package/dist/http-server.js +32 -31
- package/dist/index.js +32 -31
- package/dist/mcp-direct.js +32 -31
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1316,9 +1316,13 @@ if(!u.ok)return{advanced:!1,clean:!0,why:u.why}
|
|
|
1316
1316
|
try{const r=await e.apiClient.patch(`/api/projects/${e.projectId}/requests/${t.requestId}`,{reviewStatus:"completed",cliOrigin:{sessionId:t.coderSessionId},headSha:i,reviewRound:{...s.reviewed?{reviewed:s.reviewed}:{},clean:!0}})
|
|
1317
1317
|
if(r&&!1===r.success)return{advanced:!1,clean:!0,why:`the finish signal was refused: ${r.error??r.message??"no reason given"}`}}catch(e){return{advanced:!1,clean:!0,why:`the finish signal failed: ${(0,f.getErrorMessage)(e)}`}}return{advanced:!0,clean:!0}}function d(e){const t="DELIVERY: ESCALATE",r=e.map(e=>`${e.content?.summary??""}\n${e.content?.details??""}`).join("\n"),s=/^\(?\s*(none|n\/a|nothing|no items?|nothing to fix)\s*\)?\.?$/i,n=[],o=r.split("\n").map(e=>e.trim())
|
|
1318
1318
|
for(let e=0;e<o.length;e++)if(/^\**must_fix\**:?$/i.test(o[e]))for(let t=e+1;t<o.length&&!/^\**(nice_to_have|out_of_scope)\**:?$/i.test(o[t]);t++){const e=o[t].match(/^[-*]\s+(.+)$/)
|
|
1319
|
-
e&&!s.test(e[1])&&n.push(e[1])}
|
|
1320
|
-
|
|
1321
|
-
|
|
1319
|
+
e&&!s.test(e[1])&&n.push(e[1])}const i=/^[\s:\u2013-]*(?:(?:is|was|would be|are)\s+)?(?:not|never)\b|^[\s:\u2013-]*(?:isn'?t|wasn'?t|unnecessary)\b/i
|
|
1320
|
+
let a=-1
|
|
1321
|
+
for(let e=r.indexOf(t);e>=0;e=r.indexOf(t,e+1)){const t=r.slice(e+18).split("\n")[0]??""
|
|
1322
|
+
if(!i.test(t)){a=e
|
|
1323
|
+
break}}if(a>=0&&0===n.length)return{escalated:!0,rework:!1,reason:r.slice(a+18).replace(/^[\s:\u2013-]+/,"").split("\n").map(e=>e.trim()).find(Boolean)??"The delivery diverges from what was asked; the reviewer could not settle it."}
|
|
1324
|
+
const c=/^\W*Match\W*:\s*no\b[\s,.:;-]*(?:because\s*)?(.*)$/im.exec(r)
|
|
1325
|
+
return e.some(e=>"failure"===String(e.content?.reportStatus??""))||n.length>0||c?{escalated:!1,rework:!0,reason:n[0]??(c?.[1]?.trim()||(e[0]?.content?.summary??"").slice(0,300))}:{escalated:!1,rework:!1,reason:(e[0]?.content?.summary??"").slice(0,800)}}async function u(e,t,r,s,n,o){const i={skipped:r,...s?{reviewed:s}:{}}
|
|
1322
1326
|
let a=!1
|
|
1323
1327
|
if("no-rule"===r)try{const r=await e.apiClient.get(`/api/projects/${e.projectId}/requests/${t.requestId}`)
|
|
1324
1328
|
a=r.success&&"ready_for_review"===r.data?.status}catch{}if("no-rule"!==r||a){try{await e.apiClient.patch(`/api/projects/${e.projectId}/requests/${t.requestId}`,{reviewStatus:"completed",cliOrigin:{sessionId:t.coderSessionId},reviewRound:i})}catch(r){e.logger.error("review-fanout: finish signal failed (gate stays pending -- reconciler surfaces it)",{requestId:t.requestId,error:(0,f.getErrorMessage)(r)})}"nothing"===r&&o&&await(0,A.injectPromptToSession)(e,t.coderSessionId,o)}else await(0,A.injectPromptToSession)(e,t.coderSessionId,o)
|
|
@@ -1891,7 +1895,7 @@ if(!n)return{success:!1,message:"requestId is required",error:"Missing payload"}
|
|
|
1891
1895
|
i.info("Starting start-drive action",{requestId:n,creatorSessionId:o})
|
|
1892
1896
|
try{const e=await a.get(`/api/projects/${c}/requests/${n}`)
|
|
1893
1897
|
if(!e.success||!e.data)return{success:!1,message:`Request ${n} not found`,error:"Request not found"}
|
|
1894
|
-
const r=e.data,u=Array.isArray(r.acceptanceCriteria)&&r.acceptanceCriteria.length>0?r.acceptanceCriteria.map(e=>`- ${e?.description??e}`).join("\n"):"(none authored -- treat the description as the claim list, and say so in the receipt)",h=`Drive ${n}.\n\
|
|
1898
|
+
const r=e.data,u=Array.isArray(r.acceptanceCriteria)&&r.acceptanceCriteria.length>0?r.acceptanceCriteria.map(e=>`- ${e?.description??e}`).join("\n"):"(none authored -- treat the description as the claim list, and say so in the receipt)",h=`Drive ${n}.\n\n${function(e,t){return t?`You own this. It is a message from the user on the page of ${t}, a drive that is completed; its record is there to read (get_request_information). If it asks something that record answers, the answer is the summary you complete with, and nothing is driven. If it asks for another pass, or the record does not answer it, drive what it asks through user doors, per your instructions, and complete with the receipt. Either way end by completing (request_operations complete, requestId: "${e}"). Do not call merge; the server settles the request on your completion.`:`You own this drive request. Its acceptance criteria are CLAIMS to verify against the running system through user doors, per your instructions. Verify each claim with exact evidence, file reports for divergences beyond the criteria, and end by completing the request (request_operations complete, requestId: "${e}") with the claim -> verdict -> one-line-evidence receipt. Do not call merge; the server settles the record after your completion.`}(n,r.roundOf)}\n\n## The request\n\nTitle: ${r.title??"(untitled)"}\n\nDescription:\n${r.description||"(no description)"}\n\nAcceptance criteria (the claims):\n${u}`,p=await(0,s.spawnActionAgent)({agent:"driver",prompt:h,cwd:l,projectPath:l,projectId:c,title:/^(drive|deploy check)\b/i.test(String(r.title??""))?`[${n}] ${r.title}`.trim():`[${n}] Drive: ${r.title??""}`.trim(),requestId:n,parentSessionId:o,allowParallel:!0,skipWorktree:!0,apiClient:a,logger:i,trackChildPid:d,getDefaultModel:()=>t.cachedDefaultModel??void 0})
|
|
1895
1899
|
return p.success?(i.info("Driver spawned",{requestId:n,sessionId:p.sessionId}),{success:!0,message:`Driver spawned for ${n} (session ${p.sessionId})`}):{success:!1,message:`Failed to spawn driver for ${n}`,error:p.error}}catch(e){const t=(0,r.getErrorMessage)(e)
|
|
1896
1900
|
return i.error("start-drive action failed",{requestId:n,error:t}),{success:!1,message:`Drive dispatch failed for ${n}`,error:t}}}
|
|
1897
1901
|
const r=t(58824),s=t(28148)},93503(e,exports,t){"use strict"
|
|
@@ -1983,7 +1987,7 @@ const v=T.get(s.requestId)
|
|
|
1983
1987
|
if(v)return{success:!0,message:`${s.requestId} starts on ${v} when its current turn ends`}
|
|
1984
1988
|
try{const e=async e=>{const t=await o.get(`/api/projects/${i}/requests/${e}`)
|
|
1985
1989
|
return(t?.data??t)?.type}
|
|
1986
|
-
t.projectPath&&await(0,_.defaultBranchHasCode)(t.projectPath,e)&&(await(0,_.reportProjectHasCode)(i,!0,(e,t)=>o.patch(e,t)),await o.post(`/api/projects/${i}/requests/${s.requestId}/test-setup-offer`,{...s.creatorSessionId?{creatorSessionId:s.creatorSessionId}:{}}))}catch(e){d.warn("test-check card could not be asked for (the start goes on)",{requestId:s.requestId,error:(0,S.getErrorMessage)(e)})}const b=await(u.openDuplicates??r)(t,w,s.requestId),k=await(u.requestRecord??n)(t,s.requestId,w),I=function(e,t,r,s){const n=[`Implement ${e.requestId} ("${t?.title??""}") and own its full lifecycle. It was registered via ${e.source??"a registration door"}.`,s?"Its record, as get_request_information shows it now, is at the end of this message: start from it, and read the request again only when you need what changed since. If something it BUILDS ON does not exist in this project, call request_operations premise-block with the reason instead of starting. New content the request introduces is not a missing premise.":"Read it with get_request_information first. If something it BUILDS ON does not exist in this project, call request_operations premise-block with the reason instead of starting. New content the request introduces is not a missing premise."
|
|
1990
|
+
t.projectPath&&await(0,_.defaultBranchHasCode)(t.projectPath,e)&&(await(0,_.reportProjectHasCode)(i,!0,(e,t)=>o.patch(e,t)),await o.post(`/api/projects/${i}/requests/${s.requestId}/test-setup-offer`,{...s.creatorSessionId?{creatorSessionId:s.creatorSessionId}:{}}))}catch(e){d.warn("test-check card could not be asked for (the start goes on)",{requestId:s.requestId,error:(0,S.getErrorMessage)(e)})}const b=await(u.openDuplicates??r)(t,w,s.requestId),k=await(u.requestRecord??n)(t,s.requestId,w),I=function(e,t,r,s){const n=[`Implement ${e.requestId} ("${t?.title??""}") and own its full lifecycle. It was registered via ${e.source??"a registration door"}.`,s?"Its record, as get_request_information shows it now, is at the end of this message: start from it, and read the request again only when you need what changed since. If something it BUILDS ON does not exist in this project, call request_operations premise-block with the reason instead of starting. New content the request introduces is not a missing premise.":"Read it with get_request_information first. If something it BUILDS ON does not exist in this project, call request_operations premise-block with the reason instead of starting. New content the request introduces is not a missing premise.",...t?.roundOf?[]:[`If its acceptance criteria ALREADY hold as the code stands, do no work: complete ${e.requestId} yourself as a verification-only completion, naming exactly which criteria hold and where. Nobody else closes it: a report saying so left req000210 in progress with nobody working it.`,'Otherwise build what it asks (its own choices go in an opening brief when the pickup briefing asks for one), run the relevant validation, and complete the request with evidence. A value the request states is the value: a version number, a label, a default. Do not bump or "improve" it (two coders raised a footer version the user had just set, 2026-09-07).']]
|
|
1987
1991
|
return r.length&&n.push(`Possible duplicates already open with the same title: ${r.join(", ")}. Check before doing the work twice; if one already covers it, cancel ${e.requestId} as superseded.`),e.userNote&&n.push(`From the user: ${e.userNote}`),e.rules?.length&&n.push(function(e){const t=e.filter(e=>"told"===e.enforcement),r=e.filter(e=>"told"!==e.enforcement),s=[...t.map(e=>`- [guidance:${e.id}] ${e.text}`),...r.map(e=>`- [guidance:${e.id}] (reviewed, ${e.severity}) ${e.text}`)]
|
|
1988
1992
|
return`The workflow's guidance for this work (the user's; where an item conflicts with the brief above, the guidance wins).${r.length?" A reviewer checks the reviewed ones by id at the review gate: 'block' ones must hold, 'advise' ones are expected.":""} When the user's own words make an exception to an item for this request, record it with guidance exception (its id as listed, their words, the scope they said); when the request contradicts an item and they have not said, guidance conflict, and follow the guidance until they answer.\n${s.join("\n")}`}(e.rules)),s&&n.push(`\n# ${e.requestId}: ${t?.title??""}\n${s}`),n.join("\n")}(s,w,b,k),j="string"==typeof s.worker&&s.worker.trim()||(0,p.kindProfile)(w?.type).worker||"worker",E=(0,m.spawnToolMask)({kind:w?.type,hasTestProcess:"boolean"==typeof s.hasTestProcess?s.hasTestProcess:void 0});(0,m.hasMask)(E)&&d.info("session routing: narrowing the worker tool surface for this request",{requestId:s.requestId,worker:j,off:Object.keys(E)})
|
|
1989
1993
|
const A={p:s,req:w,worker:j,startPrompt:I,toolMask:E,deps:u}
|
package/dist/http-server.js
CHANGED
|
@@ -3637,22 +3637,22 @@ const de=async(e,r)=>(await Promise.resolve().then(()=>t(79414))).actionServerFe
|
|
|
3637
3637
|
if(G){const e="string"==typeof W?.sitting?.head?W.sitting.head:""
|
|
3638
3638
|
let t=e?null:X
|
|
3639
3639
|
if(e)try{const r=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/request-diff-stats?requestId=${encodeURIComponent(s)}&since=${encodeURIComponent(e)}`,{signal:AbortSignal.timeout(5e3)}),n=r.ok?await r.json():null
|
|
3640
|
-
n?.data&&(t={files:Array.isArray(n.data.files)?n.data.files.filter(e=>"string"==typeof e):[],additions:n.data.additions,deletions:n.data.deletions})}catch(e){P.debug("the change's own diff could not be read; it is recorded without its files",{requestId:s,error:(0,h.getErrorMessage)(e)})}le={...O?{account:O}:{},files:t?.files??[],..."number"==typeof t?.additions?{additions:t.additions}:{},..."number"==typeof t?.deletions?{deletions:t.deletions}:{}},ce=await(0,x.lookNow)(s,ae,de).catch(()=>{})}const ue=async e=>{const t=await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/validate-completion`,(0,w.validateCompletionBody)("tool",{sessionId:K,skipTestsReason:D,skipTests:F,headSha:J,...le?{change:le}:{},...e?{look:e}:{},...void 0!==oe?{authoredSinceReview:oe}:{},...ie?{reviewDelta:ie}:{},...se?{intentMoves:se}:{},...X?.files?{files:X.files}:{}}))
|
|
3640
|
+
n?.data&&(t={files:Array.isArray(n.data.files)?n.data.files.filter(e=>"string"==typeof e):[],additions:n.data.additions,deletions:n.data.deletions})}catch(e){P.debug("the change's own diff could not be read; it is recorded without its files",{requestId:s,error:(0,h.getErrorMessage)(e)})}le={...O?{account:O}:{},files:t?.files??[],..."number"==typeof t?.additions?{additions:t.additions}:{},..."number"==typeof t?.deletions?{deletions:t.deletions}:{}},ce=await(0,x.lookNow)(s,ae,de).catch(()=>{})}const ue=G&&("settle"===(0,v.kindProfile)(re??W?.type).finalize||!!X&&0===X.filesChanged&&0===X.additions&&0===X.deletions),he=async e=>{const t=await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/validate-completion`,(0,w.validateCompletionBody)("tool",{sessionId:K,skipTestsReason:D,skipTests:F,headSha:J,...ue?{diffNone:!0}:{},...le?{change:le}:{},...e?{look:e}:{},...void 0!==oe?{authoredSinceReview:oe}:{},...ie?{reviewDelta:ie}:{},...se?{intentMoves:se}:{},...X?.files?{files:X.files}:{}}))
|
|
3641
3641
|
return t?.data||t}
|
|
3642
|
-
let
|
|
3643
|
-
try{if(te=await
|
|
3644
|
-
|
|
3642
|
+
let pe=null
|
|
3643
|
+
try{if(te=await he(ce),te.canComplete&&"sitting-look"===te.plan?.action){const e=await(0,x.settleLook)(s,ae,de)
|
|
3644
|
+
pe=e.served,te=await he(e.look)}}catch(e){const t=(0,h.getErrorMessage)(e)
|
|
3645
3645
|
return P.error("Server validation failed",{requestId:s,error:t}),A({success:!1,error:"validation_request_failed"}),{content:[{type:"text",text:`Failed to validate completion: ${t}`}],isError:!0}}if(!te.canComplete){let e=`Cannot complete request ${s}: ${te.reason}\n`
|
|
3646
3646
|
if(te.blockedByTasks&&te.blockedByTasks.length>0&&(e+="\n**Tasks that must be completed or canceled first:**\n",te.blockedByTasks.forEach((t,r)=>{e+=`${r+1}. **${t.taskId}** - ${t.title} (Status: ${t.status})\n`})),te.lifoViolation&&(e+="\n**Requests that must be re-completed first (LIFO order):**\n",te.lifoViolation.blockingRequests.forEach((t,r)=>{e+=`${r+1}. **${t.requestId}** - ${t.title} (Status: ${t.status})\n`})),ne.length>0)try{const t=await C.getRequestClient().getRequest(s)
|
|
3647
3647
|
e+=`\n${function(e,t){const r=(Array.isArray(e)?e:[]).map((e,t)=>({c:e,i:t})).filter(({c:e})=>e?.id&&t.includes(String(e.id))).map(({c:e,i:t})=>{const r=Array.isArray(e.verify)?e.verify.filter(e=>"string"==typeof e):[],o=(0,n.latestRow)(e,["verify","check"]),s=o?"met"===o.verdict?"passed":"unmet"===o.verdict?"failed":o.verdict:"not run yet"
|
|
3648
3648
|
return`- [${(0,n.criterionShortKey)(String(e.id),t)}] ${r.length?`check now: ${r.map(e=>`\`${e.slice(0,120)}\``).join("; ")} (newest result: ${s})`:"no check of its own"}`})
|
|
3649
|
-
return 0===r.length?"":`Recorded all the same, as the request reads now: your account on these criteria, and their checks as they stand:\n${r.join("\n")}\nOnly the completion was refused; say so if you tell the user.`}(t?.acceptanceCriteria,ne)}`}catch{}return A({success:!1,reason:"server_blocked"}),{content:[{type:"text",text:e}],isError:!0}}if("sitting-held"===te.plan?.action)return P.info("completion held: the round stays open while the user is on its page",{requestId:s,until:te.plan.detail,look:ce,preview:
|
|
3649
|
+
return 0===r.length?"":`Recorded all the same, as the request reads now: your account on these criteria, and their checks as they stand:\n${r.join("\n")}\nOnly the completion was refused; say so if you tell the user.`}(t?.acceptanceCriteria,ne)}`}catch{}return A({success:!1,reason:"server_blocked"}),{content:[{type:"text",text:e}],isError:!0}}if("sitting-held"===te.plan?.action)return P.info("completion held: the round stays open while the user is on its page",{requestId:s,until:te.plan.detail,look:ce,preview:pe}),await(0,k.reopenOneTask)(C.getTaskClient(),s).then(()=>(0,I.clearActiveTaskCache)(),e=>P.warn("the round's one task could not be opened again; its worker opens one for its next edit",{requestId:s,error:(0,h.getErrorMessage)(e)})),A({success:!0}),{content:[{type:"text",text:[`The change is recorded on ${s}, and the round stays open: the user is on its page and may ask for more. Nothing is checked or completed yet. That happens once, for everything this round changed, when they go quiet, leave the page or press Complete, and you are told then.`,"Between changes they look at what this round made: a preview of your working copy when it serves a page, and the pictures and documents it changed, as committed. What they see must be current, so after every change run the build or the script that makes it.","When they ask for another change on this round, make it and call complete with `change`: one line saying what that change did. That records it under their words and loads what they are looking at again. Do not call merge. End your turn with that one line."].join("\n")}]}
|
|
3650
3650
|
if(G&&!i)try{const e=await C.proxyGet(`/api/projects/${E.projectId}/requests/${encodeURIComponent(s)}/rounds`)
|
|
3651
3651
|
V=function(e,t){const r=[]
|
|
3652
3652
|
for(const t of Array.isArray(e)?e:[]){const e="string"==typeof t?.changed?t.changed.trim():""
|
|
3653
3653
|
e&&!r.includes(e)&&r.push(e)}const n=(t??"").replace(/\s+/g," ").trim()
|
|
3654
|
-
return n&&!r.includes(n)&&r.push(n),r.join("\n")}(((e?.data??e)?.rounds??[]).find(e=>e?.id===s)?.changes,O)||V}catch(e){P.debug("the round's changes could not be read for its summary; this change's line stands for it",{requestId:s,error:(0,h.getErrorMessage)(e)})}const
|
|
3655
|
-
await async function(e,t,r,n){try{const o=await e.getRequestClient().getRequest(t),s=function(e,t){return(Array.isArray(e)?e:[]).flatMap(e=>{if(!e?.id||!(0,$.hasBaseline)(e)||e.retired||e.standing&&e.waived)return[]
|
|
3654
|
+
return n&&!r.includes(n)&&r.push(n),r.join("\n")}(((e?.data??e)?.rounds??[]).find(e=>e?.id===s)?.changes,O)||V}catch(e){P.debug("the round's changes could not be read for its summary; this change's line stands for it",{requestId:s,error:(0,h.getErrorMessage)(e)})}const fe=(0,x.showGiven)(U),me=te.plan,ge="answer"===me?.action
|
|
3655
|
+
ge||await async function(e,t,r,n){try{const o=await e.getRequestClient().getRequest(t),s=function(e,t){return(Array.isArray(e)?e:[]).flatMap(e=>{if(!e?.id||!(0,$.hasBaseline)(e)||e.retired||e.standing&&e.waived)return[]
|
|
3656
3656
|
const r="string"==typeof e.command?e.command.trim():""
|
|
3657
3657
|
if(!r)return[]
|
|
3658
3658
|
const n=Array.isArray(e.ledger)?e.ledger:[]
|
|
@@ -3660,35 +3660,36 @@ return t&&n.some(e=>"verify"===e?.source&&"string"==typeof e?.instrument&&e.inst
|
|
|
3660
3660
|
if(0===s.length)return
|
|
3661
3661
|
const i=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/baseline-measure`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:t,baselines:s}),signal:AbortSignal.timeout(2e4)})
|
|
3662
3662
|
n.info("baseline measurement started beside the sign-off check; the merge waits for it",{requestId:t,baselines:s.length,ok:i.ok})}catch(e){n.debug("baseline measurement could not start; the card says it was not measured",{requestId:t,error:(0,h.getErrorMessage)(e)})}}(C,s,J,P)
|
|
3663
|
-
const me
|
|
3664
|
-
if(
|
|
3665
|
-
const
|
|
3666
|
-
if(
|
|
3667
|
-
e&&await e.createToolRecord({projectId:E.projectId,requestId:s,type:"tests-skipped",metadata:{...D?{reason:D}:{},...F&&F.length>0?{skipTests:F}:{},testGate:te.gates.test,timestamp:(new Date).toISOString()}})}catch(e){P.warn("Failed to persist tests-skipped tool_record",{error:(0,h.getErrorMessage)(e)})}if(
|
|
3663
|
+
const ye=me&&fe.artifact?await C.getRequestClient().getRequest(s).then(e=>String(e?.title??"")).catch(()=>""):"",we=me&&!ge?await(0,x.startShowing)({projectId:E.projectId,post:(e,t)=>C.proxyPost(e,t),log:P,sessionExternalId:K??void 0,assetThere:e=>(0,x.assetIsThere)(E.basePath,e),resultsOf:e=>C.proxyGet(`/api/projects/${E.projectId}/results?requestId=${encodeURIComponent(e)}`).then(e=>Array.isArray(e?.data)?e.data:Array.isArray(e)?e:[])},s,fe,ye).catch(()=>""):""
|
|
3664
|
+
if(we&&P.info("showing started",{requestId:s,said:we}),"review-submit"===me?.action&&J&&X&&(X.reviewAcceptedSha=J),me?.reviewChange&&ie&&X&&(X.afterReview={...ie,outcome:me.reviewChange},"restarted"===me.reviewChange&&(X.sinceReview=ie)),!me)return A({success:!1,error:"plan_missing"}),{content:[{type:"text",text:`Server validation returned no completion plan for ${s} -- the remote is likely mid-deploy. Retry complete.`}],isError:!0}
|
|
3665
|
+
const be="testing"===me.action||"human-review"===me.action||"merge-cleared"===me.action
|
|
3666
|
+
if(be&&te.testsSkipped&&(D||F&&F.length>0))try{const e=C.getToolRecordClient()
|
|
3667
|
+
e&&await e.createToolRecord({projectId:E.projectId,requestId:s,type:"tests-skipped",metadata:{...D?{reason:D}:{},...F&&F.length>0?{skipTests:F}:{},testGate:te.gates.test,timestamp:(new Date).toISOString()}})}catch(e){P.warn("Failed to persist tests-skipped tool_record",{error:(0,h.getErrorMessage)(e)})}if(be&&M&&M.length>0&&K){const e=C.getSessionMessageClient()
|
|
3668
3668
|
if(e){let t=new Set
|
|
3669
3669
|
try{const e=await C.proxyGet(`/api/projects/${E.projectId}/session-messages`,{requestId:s,messageType:"report",limit:200}),r=Array.isArray(e)?e:e?.data??[]
|
|
3670
3670
|
t=new Set(r.filter(e=>(e?.content?.requestId??e?.content?.anchor?.id)===s).map(e=>String(e?.content?.summary??"")))}catch{}for(const r of M.slice(0,5)){const n=r.length>140?`${r.slice(0,137)}\u2026`:r
|
|
3671
3671
|
if(!t.has(n))try{await e.createReport({fromSessionId:K,status:"success",summary:n,...r.length>140?{details:r}:{},attention:"fyi",requestId:s})}catch(e){P.warn("worthKnowing note failed (completion continues)",{error:(0,h.getErrorMessage)(e)})}}P.info("worthKnowing notes processed",{count:Math.min(M.length,5),requestId:s})}}if(B&&B.length>0&&K)for(const e of B.slice(0,2))try{const t=Array.isArray(e.files)&&e.files.length>0
|
|
3672
|
-
await C.proxyPost(`/api/projects/${E.projectId}/guidance/propose`,{body:e.body,scope:t?"files":"project",...t?{pathAnchors:e.files}:{},...e.evidence?{evidence:e.evidence}:{},...e.userSaid?{userSaid:e.userSaid}:{},requestId:s,sessionExternalId:K}),P.info("guidance proposed at completion",{requestId:s})}catch(e){P.info("guidance at completion not proposed (completion continues)",{requestId:s,reason:(0,h.getErrorMessage)(e)})}const
|
|
3673
|
-
|
|
3674
|
-
e.refsSeen&&
|
|
3675
|
-
|
|
3676
|
-
if("review-
|
|
3677
|
-
if("
|
|
3678
|
-
if("
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
return{content:[{type:"text",text:`Request ${s}
|
|
3683
|
-
return{content:[{type:"text",text:`Request ${s}
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
if(
|
|
3687
|
-
|
|
3688
|
-
|
|
3672
|
+
await C.proxyPost(`/api/projects/${E.projectId}/guidance/propose`,{body:e.body,scope:t?"files":"project",...t?{pathAnchors:e.files}:{},...e.evidence?{evidence:e.evidence}:{},...e.userSaid?{userSaid:e.userSaid}:{},requestId:s,sessionExternalId:K}),P.info("guidance proposed at completion",{requestId:s})}catch(e){P.info("guidance at completion not proposed (completion continues)",{requestId:s,reason:(0,h.getErrorMessage)(e)})}const ve=C.getRequestClient()
|
|
3673
|
+
if("answer"===me.action){try{const t=await ve.updateRequest(s,{completionSummary:V,completionFormat:"markdown",completionNotChecked:"string"==typeof H&&H.trim()?H.trim():null,cliOrigin:Y,...Z,...ee})
|
|
3674
|
+
e.refsSeen&&t?.namedRefs&&(e.refsSeen.namedRefs=t.namedRefs),await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/finalize-completion`,{summary:V,acceptanceEvidence:[{evidence:"This changed nothing: its branch holds no change and no record writes into the project."}],mergeResult:{mergeCommitHash:"unknown",cleanedUp:!1,method:"answer-only",diffStats:{additions:0,deletions:0,filesChanged:0}}})}catch(e){return A({success:!1,error:"answer_finish_failed"}),{content:[{type:"text",text:`Your reply on ${s} could not be recorded: ${(0,h.getErrorMessage)(e)}. Call complete again.`}],isError:!0}}return A({success:!0}),{content:[{type:"text",text:`Your summary is the reply to the user on ${s}, and it is with them now. Nothing in the project changed, so nothing is checked and nothing waits for a sign-off: it is finished. Stop here.`}]}}for(const t of me.patches)try{const r=await ve.updateRequest(s,{...t,completionSummary:V,completionFormat:"markdown",completionNotChecked:"string"==typeof H&&H.trim()?H.trim():null,cliOrigin:Y,...Z,...ee})
|
|
3675
|
+
e.refsSeen&&r?.namedRefs&&(e.refsSeen.namedRefs=r.namedRefs)}catch(e){return A({success:!1,error:"plan_patch_failed"}),{content:[{type:"text",text:`Failed to apply completion transition (${Object.keys(t).join(", ")}): ${(0,h.getErrorMessage)(e)}`}],isError:!0}}if(A({success:!0}),"review-escalated"===me.action)return{content:[{type:"text",text:`Request ${s}: review stopped the work and it went to the user (out of review tries, or completed again unchanged). No further action from you; a human finalizes or sends back must_fix items.`}]}
|
|
3676
|
+
if("review-start"===me.action)return{content:[{type:"text",text:`Request ${s}: review started. Read-only reviewers are reading your diff. STOP here and wait: do NOT poll, sleep, or call tools to pass the time; each reviewer's report is delivered to you automatically and wakes you, so just end your turn between reports. When their reports arrive (a detailed handoff follows with the specifics), act on the findings, finish your tasks, and call complete again. If no reviewer finds anything, you are told the review was clean and the request went on with this completion: then do not complete again. After review passes, the server runs any remaining gates and messages you the exact next step (re-run tests if your fixes changed code, await human sign-off, or merge) -- wait for that and don't merge until it tells you to.`}]}
|
|
3677
|
+
if("review-submit"===me.action)return{content:[{type:"text",text:`Request ${s}: review submitted. The server is evaluating it and will message you the exact next step (re-run tests if your fixes changed code, await human sign-off, or merge) -- wait for that before acting. If a criterion is still unmet, the criteria reviewer takes another pass and reports back; address any must_fix and call complete again.`}]}
|
|
3678
|
+
if("signoff-park"===me.action)return{content:[{type:"text",text:`Request ${s}: review is complete. This request now awaits the user's sign-off in the UI -- stop here and do NOT call merge.`}]}
|
|
3679
|
+
if("promise-hold"===me.action){const e=me.detail?` (${me.detail})`:""
|
|
3680
|
+
return{content:[{type:"text",text:`Request ${s}: your change touches the test behind a promise an earlier request made${e}. Only the user changes a promise's test: on the promise card they accept your test, send the work back to put the test back, or retire the promise. Stop here and end your turn; do not call complete or merge again. You are told their answer.`}]}}if("merge-cleared-after-review"===me.action)return{content:[{type:"text",text:`Request ${s}: review is complete and all gates are clear. Call merge to finalize (do not call complete again).`}]}
|
|
3681
|
+
if("testing"===me.action){const e="human"===me.testResolver?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip). Stop here; you will receive a report when testing finishes.":"Tests are running automatically in the background. Stop here; each active test process will run and post its own report back to you."
|
|
3682
|
+
return{content:[{type:"text",text:`Request ${s}: tests are now running. ${e}\n\n## When reports arrive\nEach test process reports separately: an individual passed report does NOT mean you are cleared.\n- When every process has passed, the server advances the remaining gates automatically: agent review may start (reviewers report their findings to you), the request may wait for sign-off from the user, or the request merges. With your account of every criterion on the record (criteriaComments in this call), the server merges it and tells you so; you call nothing. Only if you are told explicitly that you are "cleared to merge" do you call \`merge\`, with evidence for the criteria you had not accounted for.\n- **Failed**: fix the issues and call \`complete\` again.\n\nDo NOT call merge, finalize, or any other tool before that explicit instruction: stop here and wait.`}]}}if("delivery-review"===me.action){const e=te.testsSkipped&&D?`\n\n_Tests skipped: ${D}_`:""
|
|
3683
|
+
return{content:[{type:"text",text:`Request ${s} is handed to the DELIVERY review, which is the last gate on this project and resolves the sign-off.${e}\n\nStop here and do NOT call merge: the review finalizes the request, or comes back to you with what it found. End your turn with one short line; your completion summary is what the user reads, so do not write it out again.`}]}}if("human-review"===me.action){const e=te.testsSkipped&&D?`\n\n_Tests skipped: ${D}_`:""
|
|
3684
|
+
return{content:[{type:"text",text:`Request ${s} submitted for human review.${e}\n\nReview is human-only for this project: the user approves the merge in the UI. Do NOT call merge yourself.`}]}}let ke,Ie
|
|
3685
|
+
try{ke=await ve.getRequest(s)}catch(e){Ie=e}const $e=(0,v.kindProfile)(re??ke?.type)
|
|
3686
|
+
if("settle"===$e.finalize)return{content:[{type:"text",text:`Request ${s} is complete. A ${$e.label.toLowerCase()} request has no branch, so nothing merges: it closes on its own record now. Stop here and do not call merge.`}]}
|
|
3687
|
+
if(void 0!==Ie)return{content:[{type:"text",text:`Request ${s} is cleared to merge, but fetching its criteria failed: ${(0,h.getErrorMessage)(Ie)}. Call merge with verification evidence for each acceptance criterion.`}]}
|
|
3688
|
+
const xe=ke?.acceptanceCriteria||[]
|
|
3689
|
+
if(!1===te?.gates?.review?.enabled&&(0,S.checksOff)(te)&&!1===te?.gates?.signoff?.enabled&&"merge"===$e.finalize&&(0===xe.length||Array.isArray(N)&&N.length>0)){P.info("gates off and account recorded: merging in the same call",{requestId:s})
|
|
3689
3690
|
const e=await(0,u.handleMergeRequest)({requestId:s,verifications:[]},E,C,q,T,j)
|
|
3690
|
-
return e?.isError?e:{...e,content:[{type:"text",text:`Request ${s}: nothing gates this project (review, tests and sign-off are off) and your account per criterion is on the record, so it merged in this call.\n\n${e.content?.[0]?.text??""}`},...e.content?.slice(1)??[]]}}const
|
|
3691
|
-
return 0===
|
|
3691
|
+
return e?.isError?e:{...e,content:[{type:"text",text:`Request ${s}: nothing gates this project (review, tests and sign-off are off) and your account per criterion is on the record, so it merged in this call.\n\n${e.content?.[0]?.text??""}`},...e.content?.slice(1)??[]]}}const Se=me.skippedReason?`\n\n_Skipped re-running tests: ${me.skippedReason}._\n`:"",_e=me.noTestsAutoMerge?"\n\n_No test processes are configured for this project, so the test gate has nothing to run; this completion merges without tests._\n":""
|
|
3692
|
+
return 0===xe.length?{content:[{type:"text",text:`Request ${s} is ready. ${Se}${_e}No acceptance criteria defined: call merge directly.`}]}:{content:[{type:"text",text:`Request ${s}: all gates are clear.${Se}${_e}\n\n## Next Step: Verify & Merge\n\n${(0,p.formatVerifyInstructions)(xe)}\n\nUse the merge operation with your verification evidence to merge to main.`}]}}catch(t){let r="An unexpected error occurred",n=""
|
|
3692
3693
|
t instanceof s.ZodError?(r="Validation error",n=t.errors.map(e=>`${e.path.join(".")}: ${e.message}`).join(", ")):t instanceof Error?(r=t.message,n=t.stack||""):n=String(t),P.error("Complete request failed",{error:r,details:n})
|
|
3693
3694
|
try{await(0,i.createFailureToolRecord)("complete-request",t,{error:r,details:n,requestId:e?.requestId},C.getToolRecordClient(),P,T,{requestId:e?.requestId,projectId:E.projectId,note:"Failed to complete request"})}catch{}return T.startTimer("tool_execution_time")({success:!1,error:t instanceof Error?t.name:"unknown"}),{content:[{type:"text",text:`Error: ${r}`}],isError:!0}}}
|
|
3694
3695
|
const n=t(65454),o=t(59860),s=t(11569),i=t(18616),a=t(35510),c=t(82860),l=t(95122),d=t(7161),u=t(34306),h=t(58824),p=t(65454),f=t(79414),m=t(67071),g=t(92456),y=t(80331),w=t(63580),b=t(52232),v=t(87780),k=t(45391),I=t(43451),$=t(70715),x=t(42692),S=t(64721),_=new Set},32283(e,exports,t){exports.def=void 0
|
package/dist/index.js
CHANGED
|
@@ -3693,22 +3693,22 @@ const de=async(e,r)=>(await Promise.resolve().then(()=>t(79414))).actionServerFe
|
|
|
3693
3693
|
if(G){const e="string"==typeof W?.sitting?.head?W.sitting.head:""
|
|
3694
3694
|
let t=e?null:X
|
|
3695
3695
|
if(e)try{const r=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/request-diff-stats?requestId=${encodeURIComponent(s)}&since=${encodeURIComponent(e)}`,{signal:AbortSignal.timeout(5e3)}),n=r.ok?await r.json():null
|
|
3696
|
-
n?.data&&(t={files:Array.isArray(n.data.files)?n.data.files.filter(e=>"string"==typeof e):[],additions:n.data.additions,deletions:n.data.deletions})}catch(e){P.debug("the change's own diff could not be read; it is recorded without its files",{requestId:s,error:(0,h.getErrorMessage)(e)})}le={...O?{account:O}:{},files:t?.files??[],..."number"==typeof t?.additions?{additions:t.additions}:{},..."number"==typeof t?.deletions?{deletions:t.deletions}:{}},ce=await(0,x.lookNow)(s,ae,de).catch(()=>{})}const ue=async e=>{const t=await C.proxyPost(`/api/projects/${_.projectId}/requests/${s}/validate-completion`,(0,w.validateCompletionBody)("tool",{sessionId:K,skipTestsReason:D,skipTests:F,headSha:J,...le?{change:le}:{},...e?{look:e}:{},...void 0!==oe?{authoredSinceReview:oe}:{},...ie?{reviewDelta:ie}:{},...se?{intentMoves:se}:{},...X?.files?{files:X.files}:{}}))
|
|
3696
|
+
n?.data&&(t={files:Array.isArray(n.data.files)?n.data.files.filter(e=>"string"==typeof e):[],additions:n.data.additions,deletions:n.data.deletions})}catch(e){P.debug("the change's own diff could not be read; it is recorded without its files",{requestId:s,error:(0,h.getErrorMessage)(e)})}le={...O?{account:O}:{},files:t?.files??[],..."number"==typeof t?.additions?{additions:t.additions}:{},..."number"==typeof t?.deletions?{deletions:t.deletions}:{}},ce=await(0,x.lookNow)(s,ae,de).catch(()=>{})}const ue=G&&("settle"===(0,v.kindProfile)(re??W?.type).finalize||!!X&&0===X.filesChanged&&0===X.additions&&0===X.deletions),he=async e=>{const t=await C.proxyPost(`/api/projects/${_.projectId}/requests/${s}/validate-completion`,(0,w.validateCompletionBody)("tool",{sessionId:K,skipTestsReason:D,skipTests:F,headSha:J,...ue?{diffNone:!0}:{},...le?{change:le}:{},...e?{look:e}:{},...void 0!==oe?{authoredSinceReview:oe}:{},...ie?{reviewDelta:ie}:{},...se?{intentMoves:se}:{},...X?.files?{files:X.files}:{}}))
|
|
3697
3697
|
return t?.data||t}
|
|
3698
|
-
let
|
|
3699
|
-
try{if(te=await
|
|
3700
|
-
|
|
3698
|
+
let pe=null
|
|
3699
|
+
try{if(te=await he(ce),te.canComplete&&"sitting-look"===te.plan?.action){const e=await(0,x.settleLook)(s,ae,de)
|
|
3700
|
+
pe=e.served,te=await he(e.look)}}catch(e){const t=(0,h.getErrorMessage)(e)
|
|
3701
3701
|
return P.error("Server validation failed",{requestId:s,error:t}),A({success:!1,error:"validation_request_failed"}),{content:[{type:"text",text:`Failed to validate completion: ${t}`}],isError:!0}}if(!te.canComplete){let e=`Cannot complete request ${s}: ${te.reason}\n`
|
|
3702
3702
|
if(te.blockedByTasks&&te.blockedByTasks.length>0&&(e+="\n**Tasks that must be completed or canceled first:**\n",te.blockedByTasks.forEach((t,r)=>{e+=`${r+1}. **${t.taskId}** - ${t.title} (Status: ${t.status})\n`})),te.lifoViolation&&(e+="\n**Requests that must be re-completed first (LIFO order):**\n",te.lifoViolation.blockingRequests.forEach((t,r)=>{e+=`${r+1}. **${t.requestId}** - ${t.title} (Status: ${t.status})\n`})),ne.length>0)try{const t=await C.getRequestClient().getRequest(s)
|
|
3703
3703
|
e+=`\n${function(e,t){const r=(Array.isArray(e)?e:[]).map((e,t)=>({c:e,i:t})).filter(({c:e})=>e?.id&&t.includes(String(e.id))).map(({c:e,i:t})=>{const r=Array.isArray(e.verify)?e.verify.filter(e=>"string"==typeof e):[],o=(0,n.latestRow)(e,["verify","check"]),s=o?"met"===o.verdict?"passed":"unmet"===o.verdict?"failed":o.verdict:"not run yet"
|
|
3704
3704
|
return`- [${(0,n.criterionShortKey)(String(e.id),t)}] ${r.length?`check now: ${r.map(e=>`\`${e.slice(0,120)}\``).join("; ")} (newest result: ${s})`:"no check of its own"}`})
|
|
3705
|
-
return 0===r.length?"":`Recorded all the same, as the request reads now: your account on these criteria, and their checks as they stand:\n${r.join("\n")}\nOnly the completion was refused; say so if you tell the user.`}(t?.acceptanceCriteria,ne)}`}catch{}return A({success:!1,reason:"server_blocked"}),{content:[{type:"text",text:e}],isError:!0}}if("sitting-held"===te.plan?.action)return P.info("completion held: the round stays open while the user is on its page",{requestId:s,until:te.plan.detail,look:ce,preview:
|
|
3705
|
+
return 0===r.length?"":`Recorded all the same, as the request reads now: your account on these criteria, and their checks as they stand:\n${r.join("\n")}\nOnly the completion was refused; say so if you tell the user.`}(t?.acceptanceCriteria,ne)}`}catch{}return A({success:!1,reason:"server_blocked"}),{content:[{type:"text",text:e}],isError:!0}}if("sitting-held"===te.plan?.action)return P.info("completion held: the round stays open while the user is on its page",{requestId:s,until:te.plan.detail,look:ce,preview:pe}),await(0,k.reopenOneTask)(C.getTaskClient(),s).then(()=>(0,I.clearActiveTaskCache)(),e=>P.warn("the round's one task could not be opened again; its worker opens one for its next edit",{requestId:s,error:(0,h.getErrorMessage)(e)})),A({success:!0}),{content:[{type:"text",text:[`The change is recorded on ${s}, and the round stays open: the user is on its page and may ask for more. Nothing is checked or completed yet. That happens once, for everything this round changed, when they go quiet, leave the page or press Complete, and you are told then.`,"Between changes they look at what this round made: a preview of your working copy when it serves a page, and the pictures and documents it changed, as committed. What they see must be current, so after every change run the build or the script that makes it.","When they ask for another change on this round, make it and call complete with `change`: one line saying what that change did. That records it under their words and loads what they are looking at again. Do not call merge. End your turn with that one line."].join("\n")}]}
|
|
3706
3706
|
if(G&&!i)try{const e=await C.proxyGet(`/api/projects/${_.projectId}/requests/${encodeURIComponent(s)}/rounds`)
|
|
3707
3707
|
V=function(e,t){const r=[]
|
|
3708
3708
|
for(const t of Array.isArray(e)?e:[]){const e="string"==typeof t?.changed?t.changed.trim():""
|
|
3709
3709
|
e&&!r.includes(e)&&r.push(e)}const n=(t??"").replace(/\s+/g," ").trim()
|
|
3710
|
-
return n&&!r.includes(n)&&r.push(n),r.join("\n")}(((e?.data??e)?.rounds??[]).find(e=>e?.id===s)?.changes,O)||V}catch(e){P.debug("the round's changes could not be read for its summary; this change's line stands for it",{requestId:s,error:(0,h.getErrorMessage)(e)})}const
|
|
3711
|
-
await async function(e,t,r,n){try{const o=await e.getRequestClient().getRequest(t),s=function(e,t){return(Array.isArray(e)?e:[]).flatMap(e=>{if(!e?.id||!(0,$.hasBaseline)(e)||e.retired||e.standing&&e.waived)return[]
|
|
3710
|
+
return n&&!r.includes(n)&&r.push(n),r.join("\n")}(((e?.data??e)?.rounds??[]).find(e=>e?.id===s)?.changes,O)||V}catch(e){P.debug("the round's changes could not be read for its summary; this change's line stands for it",{requestId:s,error:(0,h.getErrorMessage)(e)})}const fe=(0,x.showGiven)(U),me=te.plan,ge="answer"===me?.action
|
|
3711
|
+
ge||await async function(e,t,r,n){try{const o=await e.getRequestClient().getRequest(t),s=function(e,t){return(Array.isArray(e)?e:[]).flatMap(e=>{if(!e?.id||!(0,$.hasBaseline)(e)||e.retired||e.standing&&e.waived)return[]
|
|
3712
3712
|
const r="string"==typeof e.command?e.command.trim():""
|
|
3713
3713
|
if(!r)return[]
|
|
3714
3714
|
const n=Array.isArray(e.ledger)?e.ledger:[]
|
|
@@ -3716,35 +3716,36 @@ return t&&n.some(e=>"verify"===e?.source&&"string"==typeof e?.instrument&&e.inst
|
|
|
3716
3716
|
if(0===s.length)return
|
|
3717
3717
|
const i=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/baseline-measure`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:t,baselines:s}),signal:AbortSignal.timeout(2e4)})
|
|
3718
3718
|
n.info("baseline measurement started beside the sign-off check; the merge waits for it",{requestId:t,baselines:s.length,ok:i.ok})}catch(e){n.debug("baseline measurement could not start; the card says it was not measured",{requestId:t,error:(0,h.getErrorMessage)(e)})}}(C,s,J,P)
|
|
3719
|
-
const me
|
|
3720
|
-
if(
|
|
3721
|
-
const
|
|
3722
|
-
if(
|
|
3723
|
-
e&&await e.createToolRecord({projectId:_.projectId,requestId:s,type:"tests-skipped",metadata:{...D?{reason:D}:{},...F&&F.length>0?{skipTests:F}:{},testGate:te.gates.test,timestamp:(new Date).toISOString()}})}catch(e){P.warn("Failed to persist tests-skipped tool_record",{error:(0,h.getErrorMessage)(e)})}if(
|
|
3719
|
+
const ye=me&&fe.artifact?await C.getRequestClient().getRequest(s).then(e=>String(e?.title??"")).catch(()=>""):"",we=me&&!ge?await(0,x.startShowing)({projectId:_.projectId,post:(e,t)=>C.proxyPost(e,t),log:P,sessionExternalId:K??void 0,assetThere:e=>(0,x.assetIsThere)(_.basePath,e),resultsOf:e=>C.proxyGet(`/api/projects/${_.projectId}/results?requestId=${encodeURIComponent(e)}`).then(e=>Array.isArray(e?.data)?e.data:Array.isArray(e)?e:[])},s,fe,ye).catch(()=>""):""
|
|
3720
|
+
if(we&&P.info("showing started",{requestId:s,said:we}),"review-submit"===me?.action&&J&&X&&(X.reviewAcceptedSha=J),me?.reviewChange&&ie&&X&&(X.afterReview={...ie,outcome:me.reviewChange},"restarted"===me.reviewChange&&(X.sinceReview=ie)),!me)return A({success:!1,error:"plan_missing"}),{content:[{type:"text",text:`Server validation returned no completion plan for ${s} -- the remote is likely mid-deploy. Retry complete.`}],isError:!0}
|
|
3721
|
+
const be="testing"===me.action||"human-review"===me.action||"merge-cleared"===me.action
|
|
3722
|
+
if(be&&te.testsSkipped&&(D||F&&F.length>0))try{const e=C.getToolRecordClient()
|
|
3723
|
+
e&&await e.createToolRecord({projectId:_.projectId,requestId:s,type:"tests-skipped",metadata:{...D?{reason:D}:{},...F&&F.length>0?{skipTests:F}:{},testGate:te.gates.test,timestamp:(new Date).toISOString()}})}catch(e){P.warn("Failed to persist tests-skipped tool_record",{error:(0,h.getErrorMessage)(e)})}if(be&&M&&M.length>0&&K){const e=C.getSessionMessageClient()
|
|
3724
3724
|
if(e){let t=new Set
|
|
3725
3725
|
try{const e=await C.proxyGet(`/api/projects/${_.projectId}/session-messages`,{requestId:s,messageType:"report",limit:200}),r=Array.isArray(e)?e:e?.data??[]
|
|
3726
3726
|
t=new Set(r.filter(e=>(e?.content?.requestId??e?.content?.anchor?.id)===s).map(e=>String(e?.content?.summary??"")))}catch{}for(const r of M.slice(0,5)){const n=r.length>140?`${r.slice(0,137)}\u2026`:r
|
|
3727
3727
|
if(!t.has(n))try{await e.createReport({fromSessionId:K,status:"success",summary:n,...r.length>140?{details:r}:{},attention:"fyi",requestId:s})}catch(e){P.warn("worthKnowing note failed (completion continues)",{error:(0,h.getErrorMessage)(e)})}}P.info("worthKnowing notes processed",{count:Math.min(M.length,5),requestId:s})}}if(L&&L.length>0&&K)for(const e of L.slice(0,2))try{const t=Array.isArray(e.files)&&e.files.length>0
|
|
3728
|
-
await C.proxyPost(`/api/projects/${_.projectId}/guidance/propose`,{body:e.body,scope:t?"files":"project",...t?{pathAnchors:e.files}:{},...e.evidence?{evidence:e.evidence}:{},...e.userSaid?{userSaid:e.userSaid}:{},requestId:s,sessionExternalId:K}),P.info("guidance proposed at completion",{requestId:s})}catch(e){P.info("guidance at completion not proposed (completion continues)",{requestId:s,reason:(0,h.getErrorMessage)(e)})}const
|
|
3729
|
-
|
|
3730
|
-
e.refsSeen&&
|
|
3731
|
-
|
|
3732
|
-
if("review-
|
|
3733
|
-
if("
|
|
3734
|
-
if("
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
return{content:[{type:"text",text:`Request ${s}
|
|
3739
|
-
return{content:[{type:"text",text:`Request ${s}
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
if(
|
|
3743
|
-
|
|
3744
|
-
|
|
3728
|
+
await C.proxyPost(`/api/projects/${_.projectId}/guidance/propose`,{body:e.body,scope:t?"files":"project",...t?{pathAnchors:e.files}:{},...e.evidence?{evidence:e.evidence}:{},...e.userSaid?{userSaid:e.userSaid}:{},requestId:s,sessionExternalId:K}),P.info("guidance proposed at completion",{requestId:s})}catch(e){P.info("guidance at completion not proposed (completion continues)",{requestId:s,reason:(0,h.getErrorMessage)(e)})}const ve=C.getRequestClient()
|
|
3729
|
+
if("answer"===me.action){try{const t=await ve.updateRequest(s,{completionSummary:V,completionFormat:"markdown",completionNotChecked:"string"==typeof H&&H.trim()?H.trim():null,cliOrigin:Y,...Z,...ee})
|
|
3730
|
+
e.refsSeen&&t?.namedRefs&&(e.refsSeen.namedRefs=t.namedRefs),await C.proxyPost(`/api/projects/${_.projectId}/requests/${s}/finalize-completion`,{summary:V,acceptanceEvidence:[{evidence:"This changed nothing: its branch holds no change and no record writes into the project."}],mergeResult:{mergeCommitHash:"unknown",cleanedUp:!1,method:"answer-only",diffStats:{additions:0,deletions:0,filesChanged:0}}})}catch(e){return A({success:!1,error:"answer_finish_failed"}),{content:[{type:"text",text:`Your reply on ${s} could not be recorded: ${(0,h.getErrorMessage)(e)}. Call complete again.`}],isError:!0}}return A({success:!0}),{content:[{type:"text",text:`Your summary is the reply to the user on ${s}, and it is with them now. Nothing in the project changed, so nothing is checked and nothing waits for a sign-off: it is finished. Stop here.`}]}}for(const t of me.patches)try{const r=await ve.updateRequest(s,{...t,completionSummary:V,completionFormat:"markdown",completionNotChecked:"string"==typeof H&&H.trim()?H.trim():null,cliOrigin:Y,...Z,...ee})
|
|
3731
|
+
e.refsSeen&&r?.namedRefs&&(e.refsSeen.namedRefs=r.namedRefs)}catch(e){return A({success:!1,error:"plan_patch_failed"}),{content:[{type:"text",text:`Failed to apply completion transition (${Object.keys(t).join(", ")}): ${(0,h.getErrorMessage)(e)}`}],isError:!0}}if(A({success:!0}),"review-escalated"===me.action)return{content:[{type:"text",text:`Request ${s}: review stopped the work and it went to the user (out of review tries, or completed again unchanged). No further action from you; a human finalizes or sends back must_fix items.`}]}
|
|
3732
|
+
if("review-start"===me.action)return{content:[{type:"text",text:`Request ${s}: review started. Read-only reviewers are reading your diff. STOP here and wait: do NOT poll, sleep, or call tools to pass the time; each reviewer's report is delivered to you automatically and wakes you, so just end your turn between reports. When their reports arrive (a detailed handoff follows with the specifics), act on the findings, finish your tasks, and call complete again. If no reviewer finds anything, you are told the review was clean and the request went on with this completion: then do not complete again. After review passes, the server runs any remaining gates and messages you the exact next step (re-run tests if your fixes changed code, await human sign-off, or merge) -- wait for that and don't merge until it tells you to.`}]}
|
|
3733
|
+
if("review-submit"===me.action)return{content:[{type:"text",text:`Request ${s}: review submitted. The server is evaluating it and will message you the exact next step (re-run tests if your fixes changed code, await human sign-off, or merge) -- wait for that before acting. If a criterion is still unmet, the criteria reviewer takes another pass and reports back; address any must_fix and call complete again.`}]}
|
|
3734
|
+
if("signoff-park"===me.action)return{content:[{type:"text",text:`Request ${s}: review is complete. This request now awaits the user's sign-off in the UI -- stop here and do NOT call merge.`}]}
|
|
3735
|
+
if("promise-hold"===me.action){const e=me.detail?` (${me.detail})`:""
|
|
3736
|
+
return{content:[{type:"text",text:`Request ${s}: your change touches the test behind a promise an earlier request made${e}. Only the user changes a promise's test: on the promise card they accept your test, send the work back to put the test back, or retire the promise. Stop here and end your turn; do not call complete or merge again. You are told their answer.`}]}}if("merge-cleared-after-review"===me.action)return{content:[{type:"text",text:`Request ${s}: review is complete and all gates are clear. Call merge to finalize (do not call complete again).`}]}
|
|
3737
|
+
if("testing"===me.action){const e="human"===me.testResolver?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip). Stop here; you will receive a report when testing finishes.":"Tests are running automatically in the background. Stop here; each active test process will run and post its own report back to you."
|
|
3738
|
+
return{content:[{type:"text",text:`Request ${s}: tests are now running. ${e}\n\n## When reports arrive\nEach test process reports separately: an individual passed report does NOT mean you are cleared.\n- When every process has passed, the server advances the remaining gates automatically: agent review may start (reviewers report their findings to you), the request may wait for sign-off from the user, or the request merges. With your account of every criterion on the record (criteriaComments in this call), the server merges it and tells you so; you call nothing. Only if you are told explicitly that you are "cleared to merge" do you call \`merge\`, with evidence for the criteria you had not accounted for.\n- **Failed**: fix the issues and call \`complete\` again.\n\nDo NOT call merge, finalize, or any other tool before that explicit instruction: stop here and wait.`}]}}if("delivery-review"===me.action){const e=te.testsSkipped&&D?`\n\n_Tests skipped: ${D}_`:""
|
|
3739
|
+
return{content:[{type:"text",text:`Request ${s} is handed to the DELIVERY review, which is the last gate on this project and resolves the sign-off.${e}\n\nStop here and do NOT call merge: the review finalizes the request, or comes back to you with what it found. End your turn with one short line; your completion summary is what the user reads, so do not write it out again.`}]}}if("human-review"===me.action){const e=te.testsSkipped&&D?`\n\n_Tests skipped: ${D}_`:""
|
|
3740
|
+
return{content:[{type:"text",text:`Request ${s} submitted for human review.${e}\n\nReview is human-only for this project: the user approves the merge in the UI. Do NOT call merge yourself.`}]}}let ke,Ie
|
|
3741
|
+
try{ke=await ve.getRequest(s)}catch(e){Ie=e}const $e=(0,v.kindProfile)(re??ke?.type)
|
|
3742
|
+
if("settle"===$e.finalize)return{content:[{type:"text",text:`Request ${s} is complete. A ${$e.label.toLowerCase()} request has no branch, so nothing merges: it closes on its own record now. Stop here and do not call merge.`}]}
|
|
3743
|
+
if(void 0!==Ie)return{content:[{type:"text",text:`Request ${s} is cleared to merge, but fetching its criteria failed: ${(0,h.getErrorMessage)(Ie)}. Call merge with verification evidence for each acceptance criterion.`}]}
|
|
3744
|
+
const xe=ke?.acceptanceCriteria||[]
|
|
3745
|
+
if(!1===te?.gates?.review?.enabled&&(0,S.checksOff)(te)&&!1===te?.gates?.signoff?.enabled&&"merge"===$e.finalize&&(0===xe.length||Array.isArray(N)&&N.length>0)){P.info("gates off and account recorded: merging in the same call",{requestId:s})
|
|
3745
3746
|
const e=await(0,u.handleMergeRequest)({requestId:s,verifications:[]},_,C,T,q,R)
|
|
3746
|
-
return e?.isError?e:{...e,content:[{type:"text",text:`Request ${s}: nothing gates this project (review, tests and sign-off are off) and your account per criterion is on the record, so it merged in this call.\n\n${e.content?.[0]?.text??""}`},...e.content?.slice(1)??[]]}}const
|
|
3747
|
-
return 0===
|
|
3747
|
+
return e?.isError?e:{...e,content:[{type:"text",text:`Request ${s}: nothing gates this project (review, tests and sign-off are off) and your account per criterion is on the record, so it merged in this call.\n\n${e.content?.[0]?.text??""}`},...e.content?.slice(1)??[]]}}const Se=me.skippedReason?`\n\n_Skipped re-running tests: ${me.skippedReason}._\n`:"",Ee=me.noTestsAutoMerge?"\n\n_No test processes are configured for this project, so the test gate has nothing to run; this completion merges without tests._\n":""
|
|
3748
|
+
return 0===xe.length?{content:[{type:"text",text:`Request ${s} is ready. ${Se}${Ee}No acceptance criteria defined: call merge directly.`}]}:{content:[{type:"text",text:`Request ${s}: all gates are clear.${Se}${Ee}\n\n## Next Step: Verify & Merge\n\n${(0,p.formatVerifyInstructions)(xe)}\n\nUse the merge operation with your verification evidence to merge to main.`}]}}catch(t){let r="An unexpected error occurred",n=""
|
|
3748
3749
|
t instanceof s.ZodError?(r="Validation error",n=t.errors.map(e=>`${e.path.join(".")}: ${e.message}`).join(", ")):t instanceof Error?(r=t.message,n=t.stack||""):n=String(t),P.error("Complete request failed",{error:r,details:n})
|
|
3749
3750
|
try{await(0,i.createFailureToolRecord)("complete-request",t,{error:r,details:n,requestId:e?.requestId},C.getToolRecordClient(),P,q,{requestId:e?.requestId,projectId:_.projectId,note:"Failed to complete request"})}catch{}return q.startTimer("tool_execution_time")({success:!1,error:t instanceof Error?t.name:"unknown"}),{content:[{type:"text",text:`Error: ${r}`}],isError:!0}}}
|
|
3750
3751
|
const n=t(65454),o=t(59860),s=t(11569),i=t(18616),a=t(35510),c=t(82860),l=t(95122),d=t(7161),u=t(34306),h=t(58824),p=t(65454),f=t(79414),m=t(67071),g=t(92456),y=t(80331),w=t(63580),b=t(52232),v=t(87780),k=t(45391),I=t(43451),$=t(70715),x=t(42692),S=t(64721),E=new Set},32283(e,exports,t){exports.def=void 0
|
package/dist/mcp-direct.js
CHANGED
|
@@ -3529,22 +3529,22 @@ const de=async(e,r)=>(await Promise.resolve().then(()=>t(79414))).actionServerFe
|
|
|
3529
3529
|
if(G){const e="string"==typeof W?.sitting?.head?W.sitting.head:""
|
|
3530
3530
|
let t=e?null:X
|
|
3531
3531
|
if(e)try{const r=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/request-diff-stats?requestId=${encodeURIComponent(s)}&since=${encodeURIComponent(e)}`,{signal:AbortSignal.timeout(5e3)}),n=r.ok?await r.json():null
|
|
3532
|
-
n?.data&&(t={files:Array.isArray(n.data.files)?n.data.files.filter(e=>"string"==typeof e):[],additions:n.data.additions,deletions:n.data.deletions})}catch(e){P.debug("the change's own diff could not be read; it is recorded without its files",{requestId:s,error:(0,h.getErrorMessage)(e)})}le={...O?{account:O}:{},files:t?.files??[],..."number"==typeof t?.additions?{additions:t.additions}:{},..."number"==typeof t?.deletions?{deletions:t.deletions}:{}},ce=await(0,x.lookNow)(s,ae,de).catch(()=>{})}const ue=async e=>{const t=await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/validate-completion`,(0,w.validateCompletionBody)("tool",{sessionId:K,skipTestsReason:D,skipTests:F,headSha:J,...le?{change:le}:{},...e?{look:e}:{},...void 0!==oe?{authoredSinceReview:oe}:{},...ie?{reviewDelta:ie}:{},...se?{intentMoves:se}:{},...X?.files?{files:X.files}:{}}))
|
|
3532
|
+
n?.data&&(t={files:Array.isArray(n.data.files)?n.data.files.filter(e=>"string"==typeof e):[],additions:n.data.additions,deletions:n.data.deletions})}catch(e){P.debug("the change's own diff could not be read; it is recorded without its files",{requestId:s,error:(0,h.getErrorMessage)(e)})}le={...O?{account:O}:{},files:t?.files??[],..."number"==typeof t?.additions?{additions:t.additions}:{},..."number"==typeof t?.deletions?{deletions:t.deletions}:{}},ce=await(0,x.lookNow)(s,ae,de).catch(()=>{})}const ue=G&&("settle"===(0,v.kindProfile)(re??W?.type).finalize||!!X&&0===X.filesChanged&&0===X.additions&&0===X.deletions),he=async e=>{const t=await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/validate-completion`,(0,w.validateCompletionBody)("tool",{sessionId:K,skipTestsReason:D,skipTests:F,headSha:J,...ue?{diffNone:!0}:{},...le?{change:le}:{},...e?{look:e}:{},...void 0!==oe?{authoredSinceReview:oe}:{},...ie?{reviewDelta:ie}:{},...se?{intentMoves:se}:{},...X?.files?{files:X.files}:{}}))
|
|
3533
3533
|
return t?.data||t}
|
|
3534
|
-
let
|
|
3535
|
-
try{if(te=await
|
|
3536
|
-
|
|
3534
|
+
let pe=null
|
|
3535
|
+
try{if(te=await he(ce),te.canComplete&&"sitting-look"===te.plan?.action){const e=await(0,x.settleLook)(s,ae,de)
|
|
3536
|
+
pe=e.served,te=await he(e.look)}}catch(e){const t=(0,h.getErrorMessage)(e)
|
|
3537
3537
|
return P.error("Server validation failed",{requestId:s,error:t}),j({success:!1,error:"validation_request_failed"}),{content:[{type:"text",text:`Failed to validate completion: ${t}`}],isError:!0}}if(!te.canComplete){let e=`Cannot complete request ${s}: ${te.reason}\n`
|
|
3538
3538
|
if(te.blockedByTasks&&te.blockedByTasks.length>0&&(e+="\n**Tasks that must be completed or canceled first:**\n",te.blockedByTasks.forEach((t,r)=>{e+=`${r+1}. **${t.taskId}** - ${t.title} (Status: ${t.status})\n`})),te.lifoViolation&&(e+="\n**Requests that must be re-completed first (LIFO order):**\n",te.lifoViolation.blockingRequests.forEach((t,r)=>{e+=`${r+1}. **${t.requestId}** - ${t.title} (Status: ${t.status})\n`})),ne.length>0)try{const t=await C.getRequestClient().getRequest(s)
|
|
3539
3539
|
e+=`\n${function(e,t){const r=(Array.isArray(e)?e:[]).map((e,t)=>({c:e,i:t})).filter(({c:e})=>e?.id&&t.includes(String(e.id))).map(({c:e,i:t})=>{const r=Array.isArray(e.verify)?e.verify.filter(e=>"string"==typeof e):[],o=(0,n.latestRow)(e,["verify","check"]),s=o?"met"===o.verdict?"passed":"unmet"===o.verdict?"failed":o.verdict:"not run yet"
|
|
3540
3540
|
return`- [${(0,n.criterionShortKey)(String(e.id),t)}] ${r.length?`check now: ${r.map(e=>`\`${e.slice(0,120)}\``).join("; ")} (newest result: ${s})`:"no check of its own"}`})
|
|
3541
|
-
return 0===r.length?"":`Recorded all the same, as the request reads now: your account on these criteria, and their checks as they stand:\n${r.join("\n")}\nOnly the completion was refused; say so if you tell the user.`}(t?.acceptanceCriteria,ne)}`}catch{}return j({success:!1,reason:"server_blocked"}),{content:[{type:"text",text:e}],isError:!0}}if("sitting-held"===te.plan?.action)return P.info("completion held: the round stays open while the user is on its page",{requestId:s,until:te.plan.detail,look:ce,preview:
|
|
3541
|
+
return 0===r.length?"":`Recorded all the same, as the request reads now: your account on these criteria, and their checks as they stand:\n${r.join("\n")}\nOnly the completion was refused; say so if you tell the user.`}(t?.acceptanceCriteria,ne)}`}catch{}return j({success:!1,reason:"server_blocked"}),{content:[{type:"text",text:e}],isError:!0}}if("sitting-held"===te.plan?.action)return P.info("completion held: the round stays open while the user is on its page",{requestId:s,until:te.plan.detail,look:ce,preview:pe}),await(0,k.reopenOneTask)(C.getTaskClient(),s).then(()=>(0,I.clearActiveTaskCache)(),e=>P.warn("the round's one task could not be opened again; its worker opens one for its next edit",{requestId:s,error:(0,h.getErrorMessage)(e)})),j({success:!0}),{content:[{type:"text",text:[`The change is recorded on ${s}, and the round stays open: the user is on its page and may ask for more. Nothing is checked or completed yet. That happens once, for everything this round changed, when they go quiet, leave the page or press Complete, and you are told then.`,"Between changes they look at what this round made: a preview of your working copy when it serves a page, and the pictures and documents it changed, as committed. What they see must be current, so after every change run the build or the script that makes it.","When they ask for another change on this round, make it and call complete with `change`: one line saying what that change did. That records it under their words and loads what they are looking at again. Do not call merge. End your turn with that one line."].join("\n")}]}
|
|
3542
3542
|
if(G&&!i)try{const e=await C.proxyGet(`/api/projects/${E.projectId}/requests/${encodeURIComponent(s)}/rounds`)
|
|
3543
3543
|
V=function(e,t){const r=[]
|
|
3544
3544
|
for(const t of Array.isArray(e)?e:[]){const e="string"==typeof t?.changed?t.changed.trim():""
|
|
3545
3545
|
e&&!r.includes(e)&&r.push(e)}const n=(t??"").replace(/\s+/g," ").trim()
|
|
3546
|
-
return n&&!r.includes(n)&&r.push(n),r.join("\n")}(((e?.data??e)?.rounds??[]).find(e=>e?.id===s)?.changes,O)||V}catch(e){P.debug("the round's changes could not be read for its summary; this change's line stands for it",{requestId:s,error:(0,h.getErrorMessage)(e)})}const
|
|
3547
|
-
await async function(e,t,r,n){try{const o=await e.getRequestClient().getRequest(t),s=function(e,t){return(Array.isArray(e)?e:[]).flatMap(e=>{if(!e?.id||!(0,$.hasBaseline)(e)||e.retired||e.standing&&e.waived)return[]
|
|
3546
|
+
return n&&!r.includes(n)&&r.push(n),r.join("\n")}(((e?.data??e)?.rounds??[]).find(e=>e?.id===s)?.changes,O)||V}catch(e){P.debug("the round's changes could not be read for its summary; this change's line stands for it",{requestId:s,error:(0,h.getErrorMessage)(e)})}const fe=(0,x.showGiven)(U),me=te.plan,ge="answer"===me?.action
|
|
3547
|
+
ge||await async function(e,t,r,n){try{const o=await e.getRequestClient().getRequest(t),s=function(e,t){return(Array.isArray(e)?e:[]).flatMap(e=>{if(!e?.id||!(0,$.hasBaseline)(e)||e.retired||e.standing&&e.waived)return[]
|
|
3548
3548
|
const r="string"==typeof e.command?e.command.trim():""
|
|
3549
3549
|
if(!r)return[]
|
|
3550
3550
|
const n=Array.isArray(e.ledger)?e.ledger:[]
|
|
@@ -3552,35 +3552,36 @@ return t&&n.some(e=>"verify"===e?.source&&"string"==typeof e?.instrument&&e.inst
|
|
|
3552
3552
|
if(0===s.length)return
|
|
3553
3553
|
const i=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/baseline-measure`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:t,baselines:s}),signal:AbortSignal.timeout(2e4)})
|
|
3554
3554
|
n.info("baseline measurement started beside the sign-off check; the merge waits for it",{requestId:t,baselines:s.length,ok:i.ok})}catch(e){n.debug("baseline measurement could not start; the card says it was not measured",{requestId:t,error:(0,h.getErrorMessage)(e)})}}(C,s,J,P)
|
|
3555
|
-
const me
|
|
3556
|
-
if(
|
|
3557
|
-
const
|
|
3558
|
-
if(
|
|
3559
|
-
e&&await e.createToolRecord({projectId:E.projectId,requestId:s,type:"tests-skipped",metadata:{...D?{reason:D}:{},...F&&F.length>0?{skipTests:F}:{},testGate:te.gates.test,timestamp:(new Date).toISOString()}})}catch(e){P.warn("Failed to persist tests-skipped tool_record",{error:(0,h.getErrorMessage)(e)})}if(
|
|
3555
|
+
const ye=me&&fe.artifact?await C.getRequestClient().getRequest(s).then(e=>String(e?.title??"")).catch(()=>""):"",we=me&&!ge?await(0,x.startShowing)({projectId:E.projectId,post:(e,t)=>C.proxyPost(e,t),log:P,sessionExternalId:K??void 0,assetThere:e=>(0,x.assetIsThere)(E.basePath,e),resultsOf:e=>C.proxyGet(`/api/projects/${E.projectId}/results?requestId=${encodeURIComponent(e)}`).then(e=>Array.isArray(e?.data)?e.data:Array.isArray(e)?e:[])},s,fe,ye).catch(()=>""):""
|
|
3556
|
+
if(we&&P.info("showing started",{requestId:s,said:we}),"review-submit"===me?.action&&J&&X&&(X.reviewAcceptedSha=J),me?.reviewChange&&ie&&X&&(X.afterReview={...ie,outcome:me.reviewChange},"restarted"===me.reviewChange&&(X.sinceReview=ie)),!me)return j({success:!1,error:"plan_missing"}),{content:[{type:"text",text:`Server validation returned no completion plan for ${s} -- the remote is likely mid-deploy. Retry complete.`}],isError:!0}
|
|
3557
|
+
const be="testing"===me.action||"human-review"===me.action||"merge-cleared"===me.action
|
|
3558
|
+
if(be&&te.testsSkipped&&(D||F&&F.length>0))try{const e=C.getToolRecordClient()
|
|
3559
|
+
e&&await e.createToolRecord({projectId:E.projectId,requestId:s,type:"tests-skipped",metadata:{...D?{reason:D}:{},...F&&F.length>0?{skipTests:F}:{},testGate:te.gates.test,timestamp:(new Date).toISOString()}})}catch(e){P.warn("Failed to persist tests-skipped tool_record",{error:(0,h.getErrorMessage)(e)})}if(be&&M&&M.length>0&&K){const e=C.getSessionMessageClient()
|
|
3560
3560
|
if(e){let t=new Set
|
|
3561
3561
|
try{const e=await C.proxyGet(`/api/projects/${E.projectId}/session-messages`,{requestId:s,messageType:"report",limit:200}),r=Array.isArray(e)?e:e?.data??[]
|
|
3562
3562
|
t=new Set(r.filter(e=>(e?.content?.requestId??e?.content?.anchor?.id)===s).map(e=>String(e?.content?.summary??"")))}catch{}for(const r of M.slice(0,5)){const n=r.length>140?`${r.slice(0,137)}\u2026`:r
|
|
3563
3563
|
if(!t.has(n))try{await e.createReport({fromSessionId:K,status:"success",summary:n,...r.length>140?{details:r}:{},attention:"fyi",requestId:s})}catch(e){P.warn("worthKnowing note failed (completion continues)",{error:(0,h.getErrorMessage)(e)})}}P.info("worthKnowing notes processed",{count:Math.min(M.length,5),requestId:s})}}if(B&&B.length>0&&K)for(const e of B.slice(0,2))try{const t=Array.isArray(e.files)&&e.files.length>0
|
|
3564
|
-
await C.proxyPost(`/api/projects/${E.projectId}/guidance/propose`,{body:e.body,scope:t?"files":"project",...t?{pathAnchors:e.files}:{},...e.evidence?{evidence:e.evidence}:{},...e.userSaid?{userSaid:e.userSaid}:{},requestId:s,sessionExternalId:K}),P.info("guidance proposed at completion",{requestId:s})}catch(e){P.info("guidance at completion not proposed (completion continues)",{requestId:s,reason:(0,h.getErrorMessage)(e)})}const
|
|
3565
|
-
|
|
3566
|
-
e.refsSeen&&
|
|
3567
|
-
|
|
3568
|
-
if("review-
|
|
3569
|
-
if("
|
|
3570
|
-
if("
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
return{content:[{type:"text",text:`Request ${s}
|
|
3575
|
-
return{content:[{type:"text",text:`Request ${s}
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
if(
|
|
3579
|
-
|
|
3580
|
-
|
|
3564
|
+
await C.proxyPost(`/api/projects/${E.projectId}/guidance/propose`,{body:e.body,scope:t?"files":"project",...t?{pathAnchors:e.files}:{},...e.evidence?{evidence:e.evidence}:{},...e.userSaid?{userSaid:e.userSaid}:{},requestId:s,sessionExternalId:K}),P.info("guidance proposed at completion",{requestId:s})}catch(e){P.info("guidance at completion not proposed (completion continues)",{requestId:s,reason:(0,h.getErrorMessage)(e)})}const ve=C.getRequestClient()
|
|
3565
|
+
if("answer"===me.action){try{const t=await ve.updateRequest(s,{completionSummary:V,completionFormat:"markdown",completionNotChecked:"string"==typeof H&&H.trim()?H.trim():null,cliOrigin:Y,...Z,...ee})
|
|
3566
|
+
e.refsSeen&&t?.namedRefs&&(e.refsSeen.namedRefs=t.namedRefs),await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/finalize-completion`,{summary:V,acceptanceEvidence:[{evidence:"This changed nothing: its branch holds no change and no record writes into the project."}],mergeResult:{mergeCommitHash:"unknown",cleanedUp:!1,method:"answer-only",diffStats:{additions:0,deletions:0,filesChanged:0}}})}catch(e){return j({success:!1,error:"answer_finish_failed"}),{content:[{type:"text",text:`Your reply on ${s} could not be recorded: ${(0,h.getErrorMessage)(e)}. Call complete again.`}],isError:!0}}return j({success:!0}),{content:[{type:"text",text:`Your summary is the reply to the user on ${s}, and it is with them now. Nothing in the project changed, so nothing is checked and nothing waits for a sign-off: it is finished. Stop here.`}]}}for(const t of me.patches)try{const r=await ve.updateRequest(s,{...t,completionSummary:V,completionFormat:"markdown",completionNotChecked:"string"==typeof H&&H.trim()?H.trim():null,cliOrigin:Y,...Z,...ee})
|
|
3567
|
+
e.refsSeen&&r?.namedRefs&&(e.refsSeen.namedRefs=r.namedRefs)}catch(e){return j({success:!1,error:"plan_patch_failed"}),{content:[{type:"text",text:`Failed to apply completion transition (${Object.keys(t).join(", ")}): ${(0,h.getErrorMessage)(e)}`}],isError:!0}}if(j({success:!0}),"review-escalated"===me.action)return{content:[{type:"text",text:`Request ${s}: review stopped the work and it went to the user (out of review tries, or completed again unchanged). No further action from you; a human finalizes or sends back must_fix items.`}]}
|
|
3568
|
+
if("review-start"===me.action)return{content:[{type:"text",text:`Request ${s}: review started. Read-only reviewers are reading your diff. STOP here and wait: do NOT poll, sleep, or call tools to pass the time; each reviewer's report is delivered to you automatically and wakes you, so just end your turn between reports. When their reports arrive (a detailed handoff follows with the specifics), act on the findings, finish your tasks, and call complete again. If no reviewer finds anything, you are told the review was clean and the request went on with this completion: then do not complete again. After review passes, the server runs any remaining gates and messages you the exact next step (re-run tests if your fixes changed code, await human sign-off, or merge) -- wait for that and don't merge until it tells you to.`}]}
|
|
3569
|
+
if("review-submit"===me.action)return{content:[{type:"text",text:`Request ${s}: review submitted. The server is evaluating it and will message you the exact next step (re-run tests if your fixes changed code, await human sign-off, or merge) -- wait for that before acting. If a criterion is still unmet, the criteria reviewer takes another pass and reports back; address any must_fix and call complete again.`}]}
|
|
3570
|
+
if("signoff-park"===me.action)return{content:[{type:"text",text:`Request ${s}: review is complete. This request now awaits the user's sign-off in the UI -- stop here and do NOT call merge.`}]}
|
|
3571
|
+
if("promise-hold"===me.action){const e=me.detail?` (${me.detail})`:""
|
|
3572
|
+
return{content:[{type:"text",text:`Request ${s}: your change touches the test behind a promise an earlier request made${e}. Only the user changes a promise's test: on the promise card they accept your test, send the work back to put the test back, or retire the promise. Stop here and end your turn; do not call complete or merge again. You are told their answer.`}]}}if("merge-cleared-after-review"===me.action)return{content:[{type:"text",text:`Request ${s}: review is complete and all gates are clear. Call merge to finalize (do not call complete again).`}]}
|
|
3573
|
+
if("testing"===me.action){const e="human"===me.testResolver?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip). Stop here; you will receive a report when testing finishes.":"Tests are running automatically in the background. Stop here; each active test process will run and post its own report back to you."
|
|
3574
|
+
return{content:[{type:"text",text:`Request ${s}: tests are now running. ${e}\n\n## When reports arrive\nEach test process reports separately: an individual passed report does NOT mean you are cleared.\n- When every process has passed, the server advances the remaining gates automatically: agent review may start (reviewers report their findings to you), the request may wait for sign-off from the user, or the request merges. With your account of every criterion on the record (criteriaComments in this call), the server merges it and tells you so; you call nothing. Only if you are told explicitly that you are "cleared to merge" do you call \`merge\`, with evidence for the criteria you had not accounted for.\n- **Failed**: fix the issues and call \`complete\` again.\n\nDo NOT call merge, finalize, or any other tool before that explicit instruction: stop here and wait.`}]}}if("delivery-review"===me.action){const e=te.testsSkipped&&D?`\n\n_Tests skipped: ${D}_`:""
|
|
3575
|
+
return{content:[{type:"text",text:`Request ${s} is handed to the DELIVERY review, which is the last gate on this project and resolves the sign-off.${e}\n\nStop here and do NOT call merge: the review finalizes the request, or comes back to you with what it found. End your turn with one short line; your completion summary is what the user reads, so do not write it out again.`}]}}if("human-review"===me.action){const e=te.testsSkipped&&D?`\n\n_Tests skipped: ${D}_`:""
|
|
3576
|
+
return{content:[{type:"text",text:`Request ${s} submitted for human review.${e}\n\nReview is human-only for this project: the user approves the merge in the UI. Do NOT call merge yourself.`}]}}let ke,Ie
|
|
3577
|
+
try{ke=await ve.getRequest(s)}catch(e){Ie=e}const $e=(0,v.kindProfile)(re??ke?.type)
|
|
3578
|
+
if("settle"===$e.finalize)return{content:[{type:"text",text:`Request ${s} is complete. A ${$e.label.toLowerCase()} request has no branch, so nothing merges: it closes on its own record now. Stop here and do not call merge.`}]}
|
|
3579
|
+
if(void 0!==Ie)return{content:[{type:"text",text:`Request ${s} is cleared to merge, but fetching its criteria failed: ${(0,h.getErrorMessage)(Ie)}. Call merge with verification evidence for each acceptance criterion.`}]}
|
|
3580
|
+
const xe=ke?.acceptanceCriteria||[]
|
|
3581
|
+
if(!1===te?.gates?.review?.enabled&&(0,S.checksOff)(te)&&!1===te?.gates?.signoff?.enabled&&"merge"===$e.finalize&&(0===xe.length||Array.isArray(N)&&N.length>0)){P.info("gates off and account recorded: merging in the same call",{requestId:s})
|
|
3581
3582
|
const e=await(0,u.handleMergeRequest)({requestId:s,verifications:[]},E,C,q,T,R)
|
|
3582
|
-
return e?.isError?e:{...e,content:[{type:"text",text:`Request ${s}: nothing gates this project (review, tests and sign-off are off) and your account per criterion is on the record, so it merged in this call.\n\n${e.content?.[0]?.text??""}`},...e.content?.slice(1)??[]]}}const
|
|
3583
|
-
return 0===
|
|
3583
|
+
return e?.isError?e:{...e,content:[{type:"text",text:`Request ${s}: nothing gates this project (review, tests and sign-off are off) and your account per criterion is on the record, so it merged in this call.\n\n${e.content?.[0]?.text??""}`},...e.content?.slice(1)??[]]}}const Se=me.skippedReason?`\n\n_Skipped re-running tests: ${me.skippedReason}._\n`:"",_e=me.noTestsAutoMerge?"\n\n_No test processes are configured for this project, so the test gate has nothing to run; this completion merges without tests._\n":""
|
|
3584
|
+
return 0===xe.length?{content:[{type:"text",text:`Request ${s} is ready. ${Se}${_e}No acceptance criteria defined: call merge directly.`}]}:{content:[{type:"text",text:`Request ${s}: all gates are clear.${Se}${_e}\n\n## Next Step: Verify & Merge\n\n${(0,p.formatVerifyInstructions)(xe)}\n\nUse the merge operation with your verification evidence to merge to main.`}]}}catch(t){let r="An unexpected error occurred",n=""
|
|
3584
3585
|
t instanceof s.ZodError?(r="Validation error",n=t.errors.map(e=>`${e.path.join(".")}: ${e.message}`).join(", ")):t instanceof Error?(r=t.message,n=t.stack||""):n=String(t),P.error("Complete request failed",{error:r,details:n})
|
|
3585
3586
|
try{await(0,i.createFailureToolRecord)("complete-request",t,{error:r,details:n,requestId:e?.requestId},C.getToolRecordClient(),P,T,{requestId:e?.requestId,projectId:E.projectId,note:"Failed to complete request"})}catch{}return T.startTimer("tool_execution_time")({success:!1,error:t instanceof Error?t.name:"unknown"}),{content:[{type:"text",text:`Error: ${r}`}],isError:!0}}}
|
|
3586
3587
|
const n=t(65454),o=t(59860),s=t(11569),i=t(18616),a=t(35510),c=t(82860),l=t(95122),d=t(7161),u=t(34306),h=t(58824),p=t(65454),f=t(79414),m=t(67071),g=t(92456),y=t(80331),w=t(63580),b=t(52232),v=t(87780),k=t(45391),I=t(43451),$=t(70715),x=t(42692),S=t(64721),_=new Set},32283(e,exports,t){exports.def=void 0
|