alchemylab 3.0.4 → 3.0.5

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.
@@ -613,7 +613,7 @@ return`${c(s(e[1],"chart:label-cell-address"))||"series"}${t?`: ${t}`:""}${l?` b
613
613
  return`[chart: ${A[t]??t}${r?` "${r}"`:""}${d.length?`; ${d.join("; ")}`:""}]`}function x(e,t,r){switch(e){case"text:tab":return r.push("\t"),!0
614
614
  case"text:line-break":return r.push("\n"),!0
615
615
  case"text:s":return r.push(" ".repeat(Math.min(100,Number(s(t,"text:c")??1)||1))),!0
616
- default:return!1}}function S(e,t=new Map){const r=[],n=[],i=new P
616
+ default:return!1}}function S(e,t=new Map){const r=[],n=[],i=new j
617
617
  let a=0,c=0,l=null,d=null
618
618
  for(const u of e.matchAll(T)){const[,e,h,p,f,m]=u
619
619
  if(void 0!==m){if(c)continue
@@ -744,7 +744,7 @@ case"svg:title":case"svg:desc":!g&&l&&(d="svg:title"===f?"title":"desc")}}return
744
744
  return{kind:"ods",text:n.map(e=>`## Sheet: ${e.name}\n${e.text||"(empty)"}${e.figures.length?`\n\n${e.figures.join("\n")}`:""}`).join("\n\n"),units:n.length,note:"Cell values as tab-separated rows (column letters in the header); a formula shows as its value followed by (=formula). Charts and pictures are listed under their sheet."+(i?" Sheets over 5000 rows are cut off.":"")}}(a)
745
745
  case"odp":return async function(e){const{xml:t,objects:r}=await k(e,"application/vnd.oasis.opendocument.presentation","presentation"),n=function(e,t=new Map){const r=[]
746
746
  let n=null
747
- const i=new P
747
+ const i=new j
748
748
  let a=0,c=0,l=null,d=null
749
749
  for(const u of e.matchAll(T)){const[,e,h,p,f,m]=u
750
750
  if(void 0===m){if(R.has(h))f||(c+=e?-1:1)
@@ -780,7 +780,7 @@ default:throw new Error(`no text form for .${c}`)}}
780
780
  const _=t(12661),E=t(43701)
781
781
  exports.bi=52428800
782
782
  const C=5e3,q={barChart:"bar",bar3DChart:"bar",lineChart:"line",line3DChart:"line",pieChart:"pie",pie3DChart:"pie",ofPieChart:"pie",doughnutChart:"doughnut",areaChart:"area",area3DChart:"area",scatterChart:"scatter",radarChart:"radar",bubbleChart:"bubble",stockChart:"stock",surfaceChart:"surface",surface3DChart:"surface"},T=/<(\/?)([A-Za-z][\w.-]*:[\w.-]+)\b([^>]*?)(\/?)>|([^<]+)/g,R=new Set(["text:note","office:annotation","text:tracked-changes","office:forms","text:sequence-decls"]),A={circle:"pie",ring:"doughnut"}
783
- class P{constructor(){this.stack=[]}open(e,t){this.stack.push({parts:[],heading:e,listed:t})}get current(){return this.stack[this.stack.length-1]}push(e){this.current?.parts.push(e)}pushSpaced(e){const t=this.current?.parts
783
+ class j{constructor(){this.stack=[]}open(e,t){this.stack.push({parts:[],heading:e,listed:t})}get current(){return this.stack[this.stack.length-1]}push(e){this.current?.parts.push(e)}pushSpaced(e){const t=this.current?.parts
784
784
  if(!t)return
785
785
  const r=t[t.length-1]??""
786
786
  t.push(`${!r||/\s$/.test(r)?"":" "}${e} `)}close(){const e=this.stack.pop()
@@ -818,9 +818,9 @@ const n=r()
818
818
  return(0,a.isDebugToolsEnabled)()&&k.info("Stdio transport registered with server"),{server:_,transportInfo:n}}catch(e){throw k.error("Failed to initialize MCP server",{error:e}),e}})().then(()=>{(0,a.isDebugToolsEnabled)()&&k.info("MCP server initialization complete")}).catch(e=>{const t=e instanceof Error?{message:e.message,name:e.name,stack:e.stack}:String(e)
819
819
  k.error("Server initialization failed",{errorDetails:t}),process.exit(1)})}catch(e){const t=e instanceof Error?{message:e.message,name:e.name,stack:e.stack}:String(e)
820
820
  k.error("Exception during server initialization",{errorDetails:t}),process.exit(1)}process.on("SIGTERM",()=>{k.info("SIGTERM received, shutting down"),setTimeout(()=>process.exit(0),500)}),process.on("SIGINT",()=>{k.info("SIGINT received, shutting down"),setTimeout(()=>process.exit(0),500)})},50184(e,exports,t){function r(e,t,r,n,o={}){const s=u.default.resolve(e)
821
- if(P.has(s))return t.child({component:"mcp-server-registry"}).debug("Using existing server for path",{path:s}),P.get(s)
821
+ if(j.has(s))return t.child({component:"mcp-server-registry"}).debug("Using existing server for path",{path:s}),j.get(s)
822
822
  const i=new A(s,t,r,n,o)
823
- return P.set(s,i),i}var n,o=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
823
+ return j.set(s,i),i}var n,o=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
824
824
  var o=Object.getOwnPropertyDescriptor(t,r)
825
825
  o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,o)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(n=function(e){return n=Object.getOwnPropertyNames||function(e){var t=[]
826
826
  for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[t.length]=r)
@@ -895,7 +895,7 @@ r.success?this.logger.info("Successfully switched workspace to correct branch",{
895
895
  return this.logger.error("Failed to switch to request context",{requestId:e,error:r}),{success:!1,message:`Failed to switch context: ${r}`}}}async getEffectiveBasePath(e){if(!this.workspaceManager||!e)return this.basePath
896
896
  const t=await this.workspaceManager.getWorkspaceInfo(e)
897
897
  return t?.path||this.basePath}}exports.McpServer=A
898
- const P=new Map},47617(e,exports,t){exports.getServerUrl=async function(e,o){const s=process.env.OPENCODE_TUI_URL
898
+ const j=new Map},47617(e,exports,t){exports.getServerUrl=async function(e,o){const s=process.env.OPENCODE_TUI_URL
899
899
  if(n&&n.basePath===e.basePath&&n.envUrl===s)return n.result
900
900
  let i=s
901
901
  if(!i)try{const{readFileSync:r}=await Promise.resolve().then(()=>t.t(79896,23)),{join:n}=await Promise.resolve().then(()=>t.t(16928,23)),s=r(n(e.basePath,".alchemy_lab","opencode.json"),"utf8"),a=JSON.parse(s)
@@ -1308,24 +1308,26 @@ for(const t of e.guidanceNow??[])g.push(` Guidance ${t}`)}}if(m.length>0){g.pus
1308
1308
  for(const e of m){const t=e.createdByAgent?`agent ${e.createdByAgent}`:"user",r=(e.createdAt??"").slice(0,10),n=e.anchor?.selectedText?` on "${o(e.anchor.selectedText,80)}"`:""
1309
1309
  g.push(`- ${e.artifactRef?`[${e.artifactRef}]`:"Not anchored"} (${e.status}) by ${t}${r?` on ${r}`:""}${n}: ${o(e.body,240)} (annotation ${e.id})`)}}return g.push("","When you answer, cite the bracketed refs verbatim (req\u2026, document:\u2026, file:\u2026): they render as clickable links for the user."),{content:[{type:"text",text:g.join("\n")}]}}throw new r.ValidationError(`Unknown operation: ${u}. Use "set", "list" or "search-decisions".`)}catch(e){return d({operation:u,success:!1}),l.error("Directive operation failed",{operation:u,error:(0,n.getErrorMessage)(e)}),{content:[{type:"text",text:`Error (${u}): ${(0,n.getErrorMessage)(e)}`}],isError:!0}}}
1310
1310
  const r=t(59860),n=t(58824),o=(e,t)=>{const r=(e??"").replace(/\s+/g," ").trim()
1311
- return r.length>t?`${r.slice(0,t-1)}\u2026`:r}},31572(e,exports,t){exports.handleCreateDocument=async function(e,t,a,c,l,d,u){const h=c.child({tool:"create_document"}),p=l.startTimer("tool_execution_time")
1312
- try{const c=e,{requestId:l,filename:d,content:p}=c,f="string"==typeof c.comment&&c.comment.trim()?c.comment:`Created ${d}`
1313
- h.info("Creating new document",{requestId:l||"standalone",filename:d,contentLength:p.length,comment:f})
1314
- const m=t.projectId
1315
- if(!m){const e="Project ID is required. Make sure you are in a project context."
1316
- return h.warn("No project context"),{content:[{type:"text",text:`\u274c ${e}`}],isError:!0}}if(!/\.(md|html?)$/i.test(d)){const e=`Filename must end in .md (prose) or .html (a rendered page): ${d}`
1317
- return h.warn("Invalid filename extension",{filename:d}),{content:[{type:"text",text:`\u274c ${e}`}],isError:!0}}if((0,n.isProjectMapPath)(d)&&u?.sessionId){const e=await(0,r.holdNewProjectMap)((0,r.heldDocumentDepsFrom)(a,h),u.sessionId,p).catch(()=>null)
1318
- if(e)return{content:[{type:"text",text:`\u2705 ${d} started. ${(0,r.heldDocumentNote)(e)}`}]}}try{a.setProjectId(m)
1319
- const e=a.getDocumentClient()
1320
- let t,r=[]
1321
- if((0,s.hasScheduleArgs)(c)){const e=(0,s.applyScheduleArgs)(c,null)
1311
+ return r.length>t?`${r.slice(0,t-1)}\u2026`:r}},31572(e,exports,t){exports.handleCreateDocument=async function(e,a,c,l,d,u,h){const p=l.child({tool:"create_document"}),f=d.startTimer("tool_execution_time")
1312
+ try{const l=e,{requestId:d,filename:u,content:f}=l,m="string"==typeof l.comment&&l.comment.trim()?l.comment:`Created ${u}`
1313
+ p.info("Creating new document",{requestId:d||"standalone",filename:u,contentLength:f.length,comment:m})
1314
+ const g=a.projectId
1315
+ if(!g){const e="Project ID is required. Make sure you are in a project context."
1316
+ return p.warn("No project context"),{content:[{type:"text",text:`\u274c ${e}`}],isError:!0}}if(!/\.(md|html?)$/i.test(u)){const e=`Filename must end in .md (prose) or .html (a rendered page): ${u}`
1317
+ return p.warn("Invalid filename extension",{filename:u}),{content:[{type:"text",text:`\u274c ${e}`}],isError:!0}}if((0,n.isProjectMapPath)(u)&&h?.sessionId){const e=await(0,r.holdNewProjectMap)((0,r.heldDocumentDepsFrom)(c,p),h.sessionId,f).catch(()=>null)
1318
+ if(e)return{content:[{type:"text",text:`\u2705 ${u} started. ${(0,r.heldDocumentNote)(e)}`}]}}try{c.setProjectId(g)
1319
+ const e=c.getDocumentClient()
1320
+ let r,n=[]
1321
+ if((0,s.hasScheduleArgs)(l)){const e=(0,s.applyScheduleArgs)(l,null)
1322
1322
  if("problem"in e)return{content:[{type:"text",text:`\u274c ${e.problem}`}],isError:!0}
1323
- t={schedule:e.schedule},r=e.changed}const n=await e.createDocument(l,{filename:d,content:p,...u&&{cliOrigin:u},...t&&{metadata:t},..."number"==typeof c.scheduleBudgetUsd&&{budget:c.scheduleBudgetUsd,budgetSaid:"string"==typeof c.userSaid?c.userSaid:""},...void 0!==c.target&&{target:c.target,..."string"==typeof c.userSaid?{targetSaid:c.userSaid}:{}}})
1324
- h.info("Document created successfully",{documentId:n.id,filename:n.filename,requestId:l||"standalone"})
1325
- try{const e=a.getToolRecordClient()
1326
- await e.createToolRecord({type:"create-document",projectId:m,metadata:{documentId:n.id,filename:n.filename,contentLength:p.length,requestId:l,projectId:m},note:f})}catch(e){h.warn("Failed to create tool record",{recordError:e})}const o=(l?`**Request:** ${l}\n`:"**Standalone:** Yes (not tied to a request)\n")+(t?`**Schedule:** ACTIVE -- ${r.join("; ")} (${t.schedule.maxPerDay?`at most ${t.schedule.maxPerDay} request${1===t.schedule.maxPerDay?"":"s"} a day, `:""}maxInFlight ${t.schedule.maxInFlight}). The runner will periodically create ONE linked request through normal intake${c.target?.length?", only while its target is missed":""}; the user disables it by editing or deleting this document.\n`+(c.target?.length?"":"**No target:** every firing wakes you to judge the goal. If its state shows in numbers (a count, a share, an age), give it a target so it fires only while missed: a saved command that prints them (`commands` setup asks for one), then `update` this document with target.\n"):"")+("string"==typeof n.budgetNote?`**Budget:** ${n.budgetNote}\n`:"")+("string"==typeof n.targetNote?`**Target:** ${n.targetNote}\n`:"")
1327
- return{content:[{type:"text",text:`\u2705 Document created successfully!\n\n**Document ID:** ${n.id}\n**Filename:** ${n.filename}\n**Size:** ${p.length} characters\n`+o+`**Created:** ${n.createdAt}\n\n`+`The document is now stored in the tracking system and can be edited using standard file modification tools by referencing its document ID (${n.id}) instead of a file path.\n\n**Examples:**\n`+`- \`replace_string\` with \`documentId: "${n.id}"\`\n`+`- \`write_file\` with \`documentId: "${n.id}"\`\n`+`- \`file_history\` with \`documentId: "${n.id}"\``}],...t?(0,i.alchemyMeta)({threadRef:`plan:${n.id}`}):{}}}catch(e){const t=`Failed to create document: ${(0,o.getErrorMessage)(e)}`
1328
- return h.error("Failed to create document",{error:e}),{content:[{type:"text",text:`\u274c ${t}`}],isError:!0}}}catch(e){return h.error("Unexpected error in create document",{error:e}),{content:[{type:"text",text:`\u274c Unexpected error: ${(0,o.getErrorMessage)(e)}`}],isError:!0}}finally{p({tool:"create_document"})}}
1323
+ r={schedule:e.schedule},n=e.changed}const o=await e.createDocument(d,{filename:u,content:f,...h&&{cliOrigin:h},...r&&{metadata:r},..."number"==typeof l.scheduleBudgetUsd&&{budget:l.scheduleBudgetUsd,budgetSaid:"string"==typeof l.userSaid?l.userSaid:""},...void 0!==l.target&&{target:l.target,..."string"==typeof l.userSaid?{targetSaid:l.userSaid}:{}}})
1324
+ p.info("Document created successfully",{documentId:o.id,filename:o.filename,requestId:d||"standalone"})
1325
+ try{const e=c.getToolRecordClient()
1326
+ let r=d||void 0
1327
+ if(!r&&h?.sessionId)try{const{resolveRequestIdOrError:e}=await Promise.resolve().then(()=>t(36651)),n=await e(c,p,h.sessionId,"no active request")
1328
+ n?.ok&&(r=n.requestId)}catch{}await e.createToolRecord({type:"create-document",projectId:g,...r?{requestId:r}:{},metadata:{documentId:o.id,filename:o.filename,contentLength:f.length,requestId:r??d,projectId:g},note:m})}catch(e){p.warn("Failed to create tool record",{recordError:e})}const a=(d?`**Request:** ${d}\n`:"**Standalone:** Yes (not tied to a request)\n")+(r?`**Schedule:** ACTIVE -- ${n.join("; ")} (${r.schedule.maxPerDay?`at most ${r.schedule.maxPerDay} request${1===r.schedule.maxPerDay?"":"s"} a day, `:""}maxInFlight ${r.schedule.maxInFlight}). The runner will periodically create ONE linked request through normal intake${l.target?.length?", only while its target is missed":""}; the user disables it by editing or deleting this document.\n`+(l.target?.length?"":"**No target:** every firing wakes you to judge the goal. If its state shows in numbers (a count, a share, an age), give it a target so it fires only while missed: a saved command that prints them (`commands` setup asks for one), then `update` this document with target.\n"):"")+("string"==typeof o.budgetNote?`**Budget:** ${o.budgetNote}\n`:"")+("string"==typeof o.targetNote?`**Target:** ${o.targetNote}\n`:"")
1329
+ return{content:[{type:"text",text:`\u2705 Document created successfully!\n\n**Document ID:** ${o.id}\n**Filename:** ${o.filename}\n**Size:** ${f.length} characters\n`+a+`**Created:** ${o.createdAt}\n\n`+`The document is now stored in the tracking system and can be edited using standard file modification tools by referencing its document ID (${o.id}) instead of a file path.\n\n**Examples:**\n`+`- \`replace_string\` with \`documentId: "${o.id}"\`\n`+`- \`write_file\` with \`documentId: "${o.id}"\`\n`+`- \`file_history\` with \`documentId: "${o.id}"\``}],...r?(0,i.alchemyMeta)({threadRef:`plan:${o.id}`}):{}}}catch(e){const t=`Failed to create document: ${(0,o.getErrorMessage)(e)}`
1330
+ return p.error("Failed to create document",{error:e}),{content:[{type:"text",text:`\u274c ${t}`}],isError:!0}}}catch(e){return p.error("Unexpected error in create document",{error:e}),{content:[{type:"text",text:`\u274c Unexpected error: ${(0,o.getErrorMessage)(e)}`}],isError:!0}}finally{f({tool:"create_document"})}}
1329
1331
  const r=t(95040),n=t(2503),o=t(58824),s=t(72076),i=t(82272)},61391(e,exports,t){exports.def=void 0
1330
1332
  const r=t(76183),n=t(5626)
1331
1333
  exports.def={name:"document_operations",description:"Project documents, optionally linked to a request.\n\n\u2022 create - A document with content. A name ending in `.html` renders as a page in a sealed frame (no network, no other files: everything inline; no annotations); markdown is the default. scheduleAtTimes ('09:00,17:00', with scheduleOnDays 'weekdays' | 'weekends' | 'mon,thu') or scheduleIntervalSeconds makes it a SCHEDULE: a standing goal that files one linked request per firing through intake (schedulePrompt, scheduleMaxPerDay, scheduleMaxInFlight). A target makes it fire only while the target is missed. scheduleBudgetUsd: a budget the user named for the goal, their words in userSaid. On update the same params change a schedule; scheduleEnabled false (with scheduleReason) pauses it.\n\u2022 update - Edit in place (documentId, or filename such as PROJECT-MAP.md; replacements[{old_str,new_str}], mode unique|all). Keep one living deliverable current rather than a parallel one; create-snapshot before a major revision.\n\u2022 search - By content or name, project-wide; requestId narrows to that request's documents only.\n\u2022 create-snapshot / get-history / get-version / restore-version - Versions.\n\u2022 list-annotations / create-annotation / reply-to-annotation / resolve-annotation - Comments on a document.\n\u2022 create-artifact-annotation - Pin a comment to a repo file line (ref \"file:<path>\", file, line, selectedText).\n\nMarkdown: syntax highlighting, Mermaid, GFM tables, entity links ([DOC:doc######], [REQUEST:req######], [TASK:tas######]).",schema:r.DocumentOperationsSchema,fieldTags:{standardRules:["propose-standard"],filename:["create","update"],content:["create","update"],scheduleIntervalSeconds:["schedule"],scheduleAtTimes:["schedule"],scheduleOnDays:["schedule"],schedulePrompt:["schedule"],scheduleMaxPerDay:["schedule"],scheduleMaxInFlight:["schedule"],target:["schedule"],scheduleEnabled:["schedule"],scheduleBudgetUsd:["schedule"],userSaid:["schedule"],scheduleReason:["schedule"],query:["search"],includeArchived:["search"],maxResults:["search"],dateFrom:["search"],dateTo:["search"],searchIn:["search"],replacements:["update"],mode:["update"],versionNumber:["get-version","restore-version"],selectedText:["create-annotation","create-artifact-annotation"],prefixContext:["create-annotation"],suffixContext:["create-annotation"],lineHint:["create-annotation"],annotationId:["reply-to-annotation","resolve-annotation"],ref:["create-artifact-annotation"],file:["create-artifact-annotation"],line:["create-artifact-annotation"]},annotations:{title:"Document Operations",readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1},handler:(e,t)=>(0,n.handleDocumentOperations)(e,t.context,t.apiClient,t.logger,t.metrics,t.mcpServer,t.cliOrigin)}},5626(e,exports,t){exports.handleDocumentOperations=async function(e,u,h,p,f,m,g){const y=p.child({tool:"document_operations"})
@@ -1628,14 +1630,14 @@ const R=await l.ensureCorrectWorkspaceContext({taskPromoted:T.taskPromoted,reque
1628
1630
  if(!R.success)throw new Error(R.error);({normalizedPath:S,fullPath:_}=l.validateAndNormalizePath(x,r))
1629
1631
  let A=!1
1630
1632
  try{A=(await a.default.stat(_)).isDirectory()}catch{A=!1}b=l.FileOperationPhase.RECORD_CREATION,p.incrementCounter("create_directory_phase",1,{phase:b})
1631
- const{toolRecordId:P,localToolRecordId:j}=await l.createFileOperationRecords($,C,r.projectId,v.recordType,S,{directoryExists:A,userComment:h},n,o,m,p,v.metricsPrefix,f)
1632
- y=P,w=P,b=v.fileOperationPhase,p.incrementCounter("create_directory_phase",1,{phase:b})
1633
+ const{toolRecordId:j,localToolRecordId:P}=await l.createFileOperationRecords($,C,r.projectId,v.recordType,S,{directoryExists:A,userComment:h},n,o,m,p,v.metricsPrefix,f)
1634
+ y=j,w=j,b=v.fileOperationPhase,p.incrementCounter("create_directory_phase",1,{phase:b})
1633
1635
  let O=A
1634
1636
  if(!A){await a.default.mkdir(_,{recursive:!0}),m.info(`Successfully created directory ${S}`)
1635
1637
  try{const e=c.default.join(_,".gitkeep")
1636
1638
  await a.default.writeFile(e,"# This file makes the directory trackable by Git\n"),O=!0,m.info("Created .gitkeep file for Git tracking")}catch(e){m.warn("Failed to create .gitkeep file",{error:e instanceof Error?e.message:String(e)}),O=!1}}const M=Date.now()-g
1637
1639
  p.recordValue("create_directory_time",M),p.incrementCounter("create_directory_success",1),b=l.FileOperationPhase.GIT_COMMIT,p.incrementCounter("create_directory_phase",1,{phase:b})
1638
- const D=`Create directory: ${S} - ${h||"Create directory"}`,F=!A&&O?`${S}/.gitkeep`:S,N=await l.commitToGit($,F,P,j,D,r,m,p,v.metricsPrefix)
1640
+ const D=`Create directory: ${S} - ${h||"Create directory"}`,F=!A&&O?`${S}/.gitkeep`:S,N=await l.commitToGit($,F,j,P,D,r,m,p,v.metricsPrefix)
1639
1641
  b=l.FileOperationPhase.RECORD_UPDATE_SUCCESS,p.incrementCounter("create_directory_phase",1,{phase:b}),await l.updateFileOperationRecords($,y,w,S,v.recordType,`Successfully ${A?"verified":"created"} directory: ${S}`,{status:"completed",commitHash:N.commitHash,previousCommitHash:N.previousCommitHash,directoryExists:A,isDirectory:!0,userComment:h},`Successfully ${A?"verified":"created"} directory: ${S}`,n,o,m,p,v.metricsPrefix)
1640
1642
  const z=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
1641
1643
  return{content:[{type:"text",text:A?"Directory already exists":`Successfully created directory${N.commitHash?`\nCommit: ${N.commitHash.substring(0,8)}`:""}${z.requestId&&!z.permanentBranch?`\nBranch: ${z.requestId}`:""}`}]}}catch(t){if(e.taskId&&o)try{const n=t instanceof d.NotFoundError||t instanceof d.ValidationError||t instanceof u.ZodError
@@ -1666,15 +1668,15 @@ if(e.documentId)return{type:"document",target:e.documentId}
1666
1668
  throw new Error("Invalid operation: neither path nor documentId specified")})}if(0===q.length)throw new Error("At least one file or document must be specified for deletion")
1667
1669
  const T=q.filter(e=>"file"===e.type),R=q.filter(e=>"document"===e.type),A=q.length
1668
1670
  f.info("Starting mixed file and document deletion operation",{taskId:C,totalOperations:q.length,fileOperations:T.length,documentOperations:R.length,comment:S}),c.validateTaskIdFormat(C,f,s,b.metricsPrefix)
1669
- const P=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
1670
- f.info("Initial branch context",{initialBranch:P.branch,initialRequestId:P.requestId,isMain:P.isMain})
1671
- const j=T.map(e=>String(e.target).replace(/\\/g,"/")),O=[]
1671
+ const j=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
1672
+ f.info("Initial branch context",{initialBranch:j.branch,initialRequestId:j.requestId,isMain:j.isMain})
1673
+ const P=T.map(e=>String(e.target).replace(/\\/g,"/")),O=[]
1672
1674
  w=c.FileOperationPhase.TASK_VALIDATION,s.incrementCounter("delete_files_phase",1,{phase:w})
1673
- const M=j.length>0?j[0]:"document_operations",D=await c.validateTaskId(C,M,d,f,s,b.metricsPrefix),F=D?.requestId,N=await c.validateWorkItemStates(C,M,d,k,r,f,s,b.metricsPrefix),z=await c.autoPromoteTaskStatus(C,D.status,F,N.request?.status,M,d,k,f,s,b.metricsPrefix)
1675
+ const M=P.length>0?P[0]:"document_operations",D=await c.validateTaskId(C,M,d,f,s,b.metricsPrefix),F=D?.requestId,N=await c.validateWorkItemStates(C,M,d,k,r,f,s,b.metricsPrefix),z=await c.autoPromoteTaskStatus(C,D.status,F,N.request?.status,M,d,k,f,s,b.metricsPrefix)
1674
1676
  z.taskPromoted&&f.info(`Auto-promoted task ${C} (${D.title||"Untitled"}) to in_progress for mixed operations`,{taskId:C,taskTitle:D.title,previousStatus:D.status,newStatus:z.newTaskStatus,totalOperations:q.length,fileOperations:T.length,documentOperations:R.length}),z.requestPromoted&&f.info(`Auto-promoted request ${F} to in_progress for file operations`,{requestId:F,previousStatus:N.request?.status,newStatus:z.newRequestStatus,triggeringTaskId:C})
1675
1677
  const B=await c.ensureCorrectWorkspaceContext({taskPromoted:z.taskPromoted,requestId:F,context:r,operation:"delete-files",logger:f,metrics:s,metricsPrefix:b.metricsPrefix})
1676
1678
  if(!B.success)throw new Error(B.error)
1677
- for(const e of j){const{normalizedPath:t,fullPath:n}=c.validateAndNormalizePath(e,r)
1679
+ for(const e of P){const{normalizedPath:t,fullPath:n}=c.validateAndNormalizePath(e,r)
1678
1680
  O.push({normalized:t,full:n})}let L={hadUserMods:!1,userModsCommitHash:void 0}
1679
1681
  if(r.git)try{f.debug("[DELETE-FILES] Checking for user changes before mixed delete operations")
1680
1682
  const e=await(0,u.commitUserChangesBeforeToolOperation)(r.git,"delete-files",{requestId:F,taskId:C,workspaceManager:r.workspaceManager},f,s)
@@ -1773,18 +1775,18 @@ for(const e of T)A.push({type:"document",documentId:e.documentId,insertions:e.in
1773
1775
  if(A.length>0&&n.apiClient){const e=A.map(e=>e.documentId)
1774
1776
  try{await(0,p.ensureDocumentsNotLocked)(e,n.apiClient,y,m,"insert-lines-documents")}catch(e){if(e instanceof d.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
1775
1777
  throw e}}k=l.FileOperationPhase.TASK_VALIDATION,m.incrementCounter("insert_lines_phase",1,{phase:k})
1776
- const P=R.length>0?R[0].path:"document-operation",j=await l.validateTaskId(C,P,o,y,m,I.metricsPrefix),O=j?.requestId
1778
+ const j=R.length>0?R[0].path:"document-operation",P=await l.validateTaskId(C,j,o,y,m,I.metricsPrefix),O=P?.requestId
1777
1779
  let M=null
1778
1780
  R.length>0&&O&&(M=await l.validateWorkItemStates(C,R[0].path,o,i,n,y,m,I.metricsPrefix))
1779
1781
  let D={taskPromoted:!1,requestPromoted:!1}
1780
- R.length>0&&O&&M&&(D=await l.autoPromoteTaskStatus(C,j.status,O,M.request?.status,R[0].path,o,i,y,m,I.metricsPrefix),D.taskPromoted&&y.info("Auto-promoted task to in_progress for insert-lines operation",{taskId:C,requestId:O,previousStatus:j.status,newStatus:D.newTaskStatus,triggeringOperation:"insert-lines"}))
1782
+ R.length>0&&O&&M&&(D=await l.autoPromoteTaskStatus(C,P.status,O,M.request?.status,R[0].path,o,i,y,m,I.metricsPrefix),D.taskPromoted&&y.info("Auto-promoted task to in_progress for insert-lines operation",{taskId:C,requestId:O,previousStatus:P.status,newStatus:D.newTaskStatus,triggeringOperation:"insert-lines"}))
1781
1783
  const F=await l.ensureCorrectWorkspaceContext({taskPromoted:D.taskPromoted,requestId:O,context:n,operation:"insert-lines",logger:y,metrics:m,metricsPrefix:I.metricsPrefix})
1782
1784
  if(!F.success)throw new Error(F.error)
1783
1785
  if(R.length>0){y.debug("Re-validating file paths with correct workspace context",{operationCount:R.length,workspaceBasePath:n.workspaceManager?.getCurrentContext(n.currentSessionId).basePath})
1784
1786
  for(let e=0;e<R.length;e++){const t=R[e],r=q[e],{normalizedPath:o,fullPath:s}=l.validateAndNormalizePath(r.path,n)
1785
1787
  R[e]={...t,path:o,fullPath:s}}}if(A.length>0&&O)try{await(0,u.validateRequestStatusForDocumentOperation)(O,i,y,m,"insert-lines-document")}catch(e){if(e instanceof d.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
1786
1788
  throw e}k=l.FileOperationPhase.RECORD_CREATION,m.incrementCounter("insert_lines_phase",1,{phase:k})
1787
- const N=[...R.map(e=>({type:"file",path:e.path,insertions:e.insertions})),...A.map(e=>({type:"document",documentId:e.documentId,insertions:e.insertions}))],{toolRecordId:z}=await l.createFileOperationRecords(C,O,n.projectId,I.recordType,P,{operationCount:x.length,fileOperations:R.length,documentOperations:A.length,operations:N,userComment:S},o,s,y,m,I.metricsPrefix,g)
1789
+ const N=[...R.map(e=>({type:"file",path:e.path,insertions:e.insertions})),...A.map(e=>({type:"document",documentId:e.documentId,insertions:e.insertions}))],{toolRecordId:z}=await l.createFileOperationRecords(C,O,n.projectId,I.recordType,j,{operationCount:x.length,fileOperations:R.length,documentOperations:A.length,operations:N,userComment:S},o,s,y,m,I.metricsPrefix,g)
1788
1790
  if(b=z,v=z,k=I.fileOperationPhase,m.incrementCounter("insert_lines_phase",1,{phase:k}),R.length>0&&n.git)try{y.debug("[INSERT-LINES] Checking for user changes before insert operations")
1789
1791
  const e=await(0,h.commitUserChangesBeforeToolOperation)(n.git,"insert-lines",{requestId:O,taskId:C,workspaceManager:n.workspaceManager},y,m)
1790
1792
  e.userChangesCommitted&&(y.debug("[INSERT-LINES] User changes committed before insert operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),y.info("User changes committed before insert-lines operation",{taskId:C,fileOperationsCount:R.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){y.debug("[INSERT-LINES] Pre-tool commit failed, continuing with insertions",{error:e instanceof Error?e.message:String(e)}),y.warn("Pre-tool user changes commit failed, continuing with insert operation",{taskId:C,fileOperationsCount:R.length,error:e instanceof Error?e.message:String(e)})}y.debug("[INSERT-LINES] Proceeding with file operations",{fileCount:R.length})
@@ -1984,14 +1986,14 @@ const E=u.map(e=>({source:String(e.source).replace(/\\/g,"/"),destination:String
1984
1986
  v=l.FileOperationPhase.TASK_VALIDATION,f.incrementCounter("move_files_phase",1,{phase:v})
1985
1987
  const q=await l.validateTaskId(S,E[0].source,n,g,f,k.metricsPrefix),T=q?.requestId,R=await l.validateWorkItemStates(S,E[0].source,n,s,r,g,f,k.metricsPrefix),A=await l.autoPromoteTaskStatus(S,q.status,T,R.request?.status,E[0].source,n,s,g,f,k.metricsPrefix)
1986
1988
  A.taskPromoted&&g.info(`Auto-promoted task ${S} (${q.title||"Untitled"}) to in_progress for file operations`,{taskId:S,taskTitle:q.title,previousStatus:q.status,newStatus:A.newTaskStatus,operationCount:u.length}),A.requestPromoted&&g.info(`Auto-promoted request ${T} to in_progress for file operations`,{requestId:T,previousStatus:R.request?.status,newStatus:A.newRequestStatus,triggeringTaskId:S})
1987
- const P=await l.ensureCorrectWorkspaceContext({taskPromoted:A.taskPromoted,requestId:T,context:r,operation:"move-files",logger:g,metrics:f,metricsPrefix:k.metricsPrefix})
1988
- if(!P.success)throw new Error(P.error)
1989
+ const j=await l.ensureCorrectWorkspaceContext({taskPromoted:A.taskPromoted,requestId:T,context:r,operation:"move-files",logger:g,metrics:f,metricsPrefix:k.metricsPrefix})
1990
+ if(!j.success)throw new Error(j.error)
1989
1991
  for(const e of E){const{normalizedPath:t,fullPath:n}=l.validateAndNormalizePath(e.source,r),{normalizedPath:o,fullPath:s}=l.validateAndNormalizePath(e.destination,r)
1990
- C.push({source:t,destination:o,fullSource:n,fullDestination:s})}let j={hadUserMods:!1,userModsCommitHash:void 0}
1992
+ C.push({source:t,destination:o,fullSource:n,fullDestination:s})}let P={hadUserMods:!1,userModsCommitHash:void 0}
1991
1993
  if(r.git)try{g.debug("[MOVE-FILES] Checking for user changes before move operations")
1992
1994
  const e=await(0,h.commitUserChangesBeforeToolOperation)(r.git,"move-files",{requestId:T,taskId:S,workspaceManager:r.workspaceManager},g,f)
1993
- e.userChangesCommitted&&(g.debug("[MOVE-FILES] User changes committed before move operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),g.info("User changes committed before move-files operation",{taskId:S,moveOperationsCount:C.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}),j={hadUserMods:!0,userModsCommitHash:e.commitHash})}catch(e){g.debug("[MOVE-FILES] Pre-tool commit failed, continuing with move operations",{error:e instanceof Error?e.message:String(e)}),g.warn("Pre-tool user changes commit failed, continuing with move operation",{taskId:S,moveOperationsCount:C.length,error:e instanceof Error?e.message:String(e)})}g.debug("[MOVE-FILES] Proceeding with move operations",{operationCount:C.length}),v=l.FileOperationPhase.RECORD_CREATION,f.incrementCounter("move_files_phase",1,{phase:v})
1994
- const{toolRecordId:O,localToolRecordId:M}=await l.createFileOperationRecords(S,T,r.projectId,k.recordType,C[0].source,{operationCount:u.length,operations:C.map(e=>({source:e.source,destination:e.destination})),userComment:I,hadUserMods:j.hadUserMods,userModsCommitHash:j.userModsCommitHash},n,o,g,f,k.metricsPrefix,m)
1995
+ e.userChangesCommitted&&(g.debug("[MOVE-FILES] User changes committed before move operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),g.info("User changes committed before move-files operation",{taskId:S,moveOperationsCount:C.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}),P={hadUserMods:!0,userModsCommitHash:e.commitHash})}catch(e){g.debug("[MOVE-FILES] Pre-tool commit failed, continuing with move operations",{error:e instanceof Error?e.message:String(e)}),g.warn("Pre-tool user changes commit failed, continuing with move operation",{taskId:S,moveOperationsCount:C.length,error:e instanceof Error?e.message:String(e)})}g.debug("[MOVE-FILES] Proceeding with move operations",{operationCount:C.length}),v=l.FileOperationPhase.RECORD_CREATION,f.incrementCounter("move_files_phase",1,{phase:v})
1996
+ const{toolRecordId:O,localToolRecordId:M}=await l.createFileOperationRecords(S,T,r.projectId,k.recordType,C[0].source,{operationCount:u.length,operations:C.map(e=>({source:e.source,destination:e.destination})),userComment:I,hadUserMods:P.hadUserMods,userModsCommitHash:P.userModsCommitHash},n,o,g,f,k.metricsPrefix,m)
1995
1997
  w=O,b=O,v=k.fileOperationPhase,f.incrementCounter("move_files_phase",1,{phase:v})
1996
1998
  const D=[]
1997
1999
  let F=0
@@ -2006,7 +2008,7 @@ if(F>0){v=l.FileOperationPhase.GIT_COMMIT,f.incrementCounter("move_files_phase",
2006
2008
  const e=D.filter(e=>e.success),t=1===e.length?`Move ${e[0].isDirectory?"directory":"file"} from ${e[0].operation.source} to ${e[0].operation.destination} - ${I}`:`Move ${e.length} ${1===e.length?"item":"items"} - ${I}`
2007
2009
  z=await l.commitToGit(S,e.flatMap(e=>[e.operation.source,e.operation.destination]),O,M,t,r,g,f,k.metricsPrefix)}v=l.FileOperationPhase.RECORD_UPDATE_SUCCESS,f.incrementCounter("move_files_phase",1,{phase:v})
2008
2010
  const B=D.filter(e=>e.success),L=D.filter(e=>!e.success)
2009
- await l.updateFileOperationRecords(S,w,b,C[0].source,k.recordType,F===u.length?`Successfully moved all ${u.length} items`:`Moved ${F}/${u.length} items successfully`,{status:F===u.length?"completed":"partial_success",commitHash:z?.commitHash,previousCommitHash:z?.previousCommitHash,operationCount:u.length,successCount:F,failureCount:u.length-F,successfulOperations:B.map(e=>({source:e.operation.source,destination:e.operation.destination,isDirectory:e.isDirectory})),failedOperations:L.map(e=>({source:e.operation.source,destination:e.operation.destination,error:e.error})),userComment:I,hadUserMods:j.hadUserMods,userModsCommitHash:j.userModsCommitHash},F===u.length?`Successfully moved all ${u.length} items`:`Moved ${F}/${u.length} items successfully`,n,o,g,f,k.metricsPrefix)
2011
+ await l.updateFileOperationRecords(S,w,b,C[0].source,k.recordType,F===u.length?`Successfully moved all ${u.length} items`:`Moved ${F}/${u.length} items successfully`,{status:F===u.length?"completed":"partial_success",commitHash:z?.commitHash,previousCommitHash:z?.previousCommitHash,operationCount:u.length,successCount:F,failureCount:u.length-F,successfulOperations:B.map(e=>({source:e.operation.source,destination:e.operation.destination,isDirectory:e.isDirectory})),failedOperations:L.map(e=>({source:e.operation.source,destination:e.operation.destination,error:e.error})),userComment:I,hadUserMods:P.hadUserMods,userModsCommitHash:P.userModsCommitHash},F===u.length?`Successfully moved all ${u.length} items`:`Moved ${F}/${u.length} items successfully`,n,o,g,f,k.metricsPrefix)
2010
2012
  const H=r.getCurrentBranchContext?await r.getCurrentBranchContext():{branch:null,requestId:null,isMain:!0}
2011
2013
  let U=""
2012
2014
  if(F===u.length)U=`Successfully moved all ${u.length} ${1===u.length?"item":"items"}`
@@ -2110,10 +2112,10 @@ try{const _=e,{enforceActiveTask:E}=await Promise.resolve().then(()=>t(43451)),C
2110
2112
  if("errorResult"in C)return C.errorResult
2111
2113
  const{taskId:q}=C,{operations:T,fuzzy_match:R=!0,comment:A}=_
2112
2114
  I.info("Replace in files batch operation",{taskId:q,operationCount:T.length,totalReplacements:T.reduce((e,t)=>e+t.replacements.length,0),globalFuzzyMatch:R,comment:A})
2113
- const P=T.filter(e=>e.documentId).map(e=>e.documentId)
2114
- if(P.length>0&&r.apiClient)try{await(0,y.ensureDocumentsNotLocked)(P,r.apiClient,I,l,"replace_in_files-documents")}catch(e){if(e instanceof f.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2115
+ const j=T.filter(e=>e.documentId).map(e=>e.documentId)
2116
+ if(j.length>0&&r.apiClient)try{await(0,y.ensureDocumentsNotLocked)(j,r.apiClient,I,l,"replace_in_files-documents")}catch(e){if(e instanceof f.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2115
2117
  throw e}S=h.FileOperationPhase.TASK_VALIDATION,l.incrementCounter("replace_in_files_phase",1,{phase:S})
2116
- const j=T[0],O=j.documentId?`document:${j.documentId}`:j.path
2118
+ const P=T[0],O=P.documentId?`document:${P.documentId}`:P.path
2117
2119
  let M=Date.now()
2118
2120
  const D=await h.validateTaskId(q,O,s,I,l,"replace_in_files")
2119
2121
  Date.now()
@@ -2126,7 +2128,7 @@ const t=await h.autoPromoteTaskStatus(q,D.status,F,e.request?.status,O,s,a,I,l,"
2126
2128
  t.taskPromoted&&I.info("Auto-promoted task to in_progress",{taskId:q,requestId:F,previousStatus:D.status,newStatus:t.newTaskStatus}),Date.now(),M=Date.now()
2127
2129
  const n=await h.ensureCorrectWorkspaceContext({taskPromoted:t.taskPromoted,requestId:F,context:r,operation:"replace_in_files",logger:I,metrics:l,metricsPrefix:"replace_in_files"})
2128
2130
  if(!n.success)throw new Error(n.error)
2129
- Date.now(),z=!0}if(P.length>0&&F)try{await(0,m.validateRequestStatusForDocumentOperation)(F,a,I,l,"replace_in_files-documents")}catch(e){if(e instanceof f.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2131
+ Date.now(),z=!0}if(j.length>0&&F)try{await(0,m.validateRequestStatusForDocumentOperation)(F,a,I,l,"replace_in_files-documents")}catch(e){if(e instanceof f.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2130
2132
  throw e}M=Date.now()
2131
2133
  const B=new Map
2132
2134
  if(I.info("\u{1f50d} Starting external edit detection",{hasFileOperations:N,hasGit:!!r.git,operationCount:T.length}),N&&r.git)for(const e of T)if(e.path&&!e.documentId)try{const t=h.validateAndNormalizePath(e.path,r),n=await d.default.readFile(t.fullPath,"utf8"),o=void 0!==e.fuzzy_match?e.fuzzy_match:R,s=[]
@@ -2188,13 +2190,13 @@ const T=S.filter(e=>e.path),R=S.filter(e=>e.documentId)
2188
2190
  w.info("Operation breakdown",{fileOperations:T.length,documentOperations:R.length})
2189
2191
  const A=[]
2190
2192
  for(const e of T){const{normalizedPath:t,fullPath:r}=l.validateAndNormalizePath(e.path,n)
2191
- A.push({type:"file",path:t,fullPath:r,replacements:e.replacements.map(e=>({lines:(0,g.parseLineSpec)(e.lines),content:e.content}))})}const P=[]
2193
+ A.push({type:"file",path:t,fullPath:r,replacements:e.replacements.map(e=>({lines:(0,g.parseLineSpec)(e.lines),content:e.content}))})}const j=[]
2192
2194
  if(R.length>0&&!n.documentFileManager)throw new Error("Document file manager not available - cannot process document operations")
2193
- for(const e of R)P.push({type:"document",documentId:e.documentId,replacements:e.replacements.map(e=>({lines:(0,g.parseLineSpec)(e.lines),content:e.content}))})
2194
- if(P.length>0&&n.apiClient){const e=P.map(e=>e.documentId)
2195
+ for(const e of R)j.push({type:"document",documentId:e.documentId,replacements:e.replacements.map(e=>({lines:(0,g.parseLineSpec)(e.lines),content:e.content}))})
2196
+ if(j.length>0&&n.apiClient){const e=j.map(e=>e.documentId)
2195
2197
  try{await(0,p.ensureDocumentsNotLocked)(e,n.apiClient,w,m,"replace-lines-documents")}catch(e){if(e instanceof d.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2196
2198
  throw e}}I=l.FileOperationPhase.TASK_VALIDATION,m.incrementCounter("replace_lines_phase",1,{phase:I})
2197
- const j=A.length>0?A[0].path:"document-operation",O=await l.validateTaskId(q,j,o,w,m,$.metricsPrefix),M=O?.requestId
2199
+ const P=A.length>0?A[0].path:"document-operation",O=await l.validateTaskId(q,P,o,w,m,$.metricsPrefix),M=O?.requestId
2198
2200
  let D=null
2199
2201
  A.length>0&&M&&(D=await l.validateWorkItemStates(q,A[0].path,o,i,n,w,m,$.metricsPrefix))
2200
2202
  let F={taskPromoted:!1,requestPromoted:!1}
@@ -2203,9 +2205,9 @@ const N=await l.ensureCorrectWorkspaceContext({taskPromoted:F.taskPromoted,reque
2203
2205
  if(!N.success)throw new Error(N.error)
2204
2206
  if(A.length>0){w.debug("Re-validating file paths with correct workspace context",{operationCount:A.length,workspaceBasePath:n.workspaceManager?.getCurrentContext(n.currentSessionId).basePath})
2205
2207
  for(let e=0;e<A.length;e++){const t=A[e],r=T[e],{normalizedPath:o,fullPath:s}=l.validateAndNormalizePath(r.path,n)
2206
- A[e]={...t,path:o,fullPath:s}}}if(P.length>0&&M)try{await(0,u.validateRequestStatusForDocumentOperation)(M,i,w,m,"replace-lines-document")}catch(e){if(e instanceof d.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2208
+ A[e]={...t,path:o,fullPath:s}}}if(j.length>0&&M)try{await(0,u.validateRequestStatusForDocumentOperation)(M,i,w,m,"replace-lines-document")}catch(e){if(e instanceof d.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2207
2209
  throw e}I=l.FileOperationPhase.RECORD_CREATION,m.incrementCounter("replace_lines_phase",1,{phase:I})
2208
- const z=[...A.map(e=>({type:"file",path:e.path,replacements:e.replacements})),...P.map(e=>({type:"document",documentId:e.documentId,replacements:e.replacements}))],{toolRecordId:B}=await l.createFileOperationRecords(q,M,n.projectId,$.recordType,j,{operationCount:S.length,fileOperations:A.length,documentOperations:P.length,operations:z,userComment:_},o,s,w,m,$.metricsPrefix,y)
2210
+ const z=[...A.map(e=>({type:"file",path:e.path,replacements:e.replacements})),...j.map(e=>({type:"document",documentId:e.documentId,replacements:e.replacements}))],{toolRecordId:B}=await l.createFileOperationRecords(q,M,n.projectId,$.recordType,P,{operationCount:S.length,fileOperations:A.length,documentOperations:j.length,operations:z,userComment:_},o,s,w,m,$.metricsPrefix,y)
2209
2211
  if(v=B,k=B,I=$.fileOperationPhase,m.incrementCounter("replace_lines_phase",1,{phase:I}),A.length>0&&n.git)try{w.debug("[REPLACE-LINES] Checking for user changes before replace operations")
2210
2212
  const e=await(0,h.commitUserChangesBeforeToolOperation)(n.git,"replace-lines",{requestId:M,taskId:q,workspaceManager:n.workspaceManager},w,m)
2211
2213
  e.userChangesCommitted&&(w.debug("[REPLACE-LINES] User changes committed before replace operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),w.info("User changes committed before replace-lines operation",{taskId:q,fileOperationsCount:A.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){w.debug("[REPLACE-LINES] Pre-tool commit failed, continuing with replacements",{error:e instanceof Error?e.message:String(e)}),w.warn("Pre-tool user changes commit failed, continuing with replace operation",{taskId:q,fileOperationsCount:A.length,error:e instanceof Error?e.message:String(e)})}w.debug("[REPLACE-LINES] Proceeding with file operations",{fileCount:A.length})
@@ -2214,19 +2216,19 @@ let H=0,U=0,W=0,G=0
2214
2216
  for(const e of A){const t={type:"file",path:e.path,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0,totalLinesReplaced:0,totalLinesAdded:0}
2215
2217
  try{if(await c.default.access(e.fullPath),!(await c.default.stat(e.fullPath)).isFile())throw new Error(`Path is not a file: ${e.path}`)
2216
2218
  const n=await c.default.readFile(e.fullPath,"utf8"),{newContent:o,results:s}=await r(n,e.replacements)
2217
- t.replacements=s,t.successfulReplacements=s.filter(e=>e.success).length,t.failedReplacements=s.filter(e=>!e.success).length,t.totalLinesReplaced=s.filter(e=>e.success).reduce((e,t)=>e+(t.linesReplaced||0),0),t.totalLinesAdded=s.filter(e=>e.success).reduce((e,t)=>e+(t.linesAdded||0),0),o!==n&&t.successfulReplacements>0?(await c.default.writeFile(e.fullPath,o,"utf8"),t.success=!0,G++,w.info("File updated successfully",{path:e.path,successfulReplacements:t.successfulReplacements,failedReplacements:t.failedReplacements,linesReplaced:t.totalLinesReplaced,linesAdded:t.totalLinesAdded})):0===t.failedReplacements&&(t.success=!0),H+=t.failedReplacements,U+=t.totalLinesReplaced,W+=t.totalLinesAdded}catch(r){t.error=(0,f.getErrorMessage)(r),t.failedReplacements=e.replacements.length,H+=t.failedReplacements,w.error("File operation failed",{path:e.path,error:t.error})}L.push(t)}for(const e of P){const t={type:"document",documentId:e.documentId,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0,totalLinesReplaced:0,totalLinesAdded:0}
2219
+ t.replacements=s,t.successfulReplacements=s.filter(e=>e.success).length,t.failedReplacements=s.filter(e=>!e.success).length,t.totalLinesReplaced=s.filter(e=>e.success).reduce((e,t)=>e+(t.linesReplaced||0),0),t.totalLinesAdded=s.filter(e=>e.success).reduce((e,t)=>e+(t.linesAdded||0),0),o!==n&&t.successfulReplacements>0?(await c.default.writeFile(e.fullPath,o,"utf8"),t.success=!0,G++,w.info("File updated successfully",{path:e.path,successfulReplacements:t.successfulReplacements,failedReplacements:t.failedReplacements,linesReplaced:t.totalLinesReplaced,linesAdded:t.totalLinesAdded})):0===t.failedReplacements&&(t.success=!0),H+=t.failedReplacements,U+=t.totalLinesReplaced,W+=t.totalLinesAdded}catch(r){t.error=(0,f.getErrorMessage)(r),t.failedReplacements=e.replacements.length,H+=t.failedReplacements,w.error("File operation failed",{path:e.path,error:t.error})}L.push(t)}for(const e of j){const t={type:"document",documentId:e.documentId,success:!1,replacements:[],successfulReplacements:0,failedReplacements:0,totalLinesReplaced:0,totalLinesAdded:0}
2218
2220
  try{const o=await n.documentFileManager.getDocumentAsFile(e.documentId),s=n.documentFileManager.getCachedDocumentInfo(e.documentId)
2219
2221
  t.filename=s?.filename
2220
2222
  const i=await c.default.readFile(o,"utf8"),{newContent:a,results:l}=await r(i,e.replacements)
2221
- t.replacements=l,t.successfulReplacements=l.filter(e=>e.success).length,t.failedReplacements=l.filter(e=>!e.success).length,t.totalLinesReplaced=l.filter(e=>e.success).reduce((e,t)=>e+(t.linesReplaced||0),0),t.totalLinesAdded=l.filter(e=>e.success).reduce((e,t)=>e+(t.linesAdded||0),0),a!==i&&t.successfulReplacements>0?(await c.default.writeFile(o,a,"utf8"),n.documentFileManager.markForSync(e.documentId),t.success=!0,G++,w.info("Document updated successfully",{documentId:e.documentId,filename:t.filename,successfulReplacements:t.successfulReplacements,failedReplacements:t.failedReplacements,linesReplaced:t.totalLinesReplaced,linesAdded:t.totalLinesAdded})):0===t.failedReplacements&&(t.success=!0),H+=t.failedReplacements,U+=t.totalLinesReplaced,W+=t.totalLinesAdded}catch(r){t.error=(0,f.getErrorMessage)(r),t.failedReplacements=e.replacements.length,H+=t.failedReplacements,w.error("Document operation failed",{documentId:e.documentId,error:t.error})}L.push(t)}if(P.length>0)try{for(const e of P){const t=L.find(t=>t.documentId===e.documentId)
2223
+ t.replacements=l,t.successfulReplacements=l.filter(e=>e.success).length,t.failedReplacements=l.filter(e=>!e.success).length,t.totalLinesReplaced=l.filter(e=>e.success).reduce((e,t)=>e+(t.linesReplaced||0),0),t.totalLinesAdded=l.filter(e=>e.success).reduce((e,t)=>e+(t.linesAdded||0),0),a!==i&&t.successfulReplacements>0?(await c.default.writeFile(o,a,"utf8"),n.documentFileManager.markForSync(e.documentId),t.success=!0,G++,w.info("Document updated successfully",{documentId:e.documentId,filename:t.filename,successfulReplacements:t.successfulReplacements,failedReplacements:t.failedReplacements,linesReplaced:t.totalLinesReplaced,linesAdded:t.totalLinesAdded})):0===t.failedReplacements&&(t.success=!0),H+=t.failedReplacements,U+=t.totalLinesReplaced,W+=t.totalLinesAdded}catch(r){t.error=(0,f.getErrorMessage)(r),t.failedReplacements=e.replacements.length,H+=t.failedReplacements,w.error("Document operation failed",{documentId:e.documentId,error:t.error})}L.push(t)}if(j.length>0)try{for(const e of j){const t=L.find(t=>t.documentId===e.documentId)
2222
2224
  t?.success&&await n.documentFileManager.syncDocument(e.documentId)}}catch(e){w.warn("Some documents may not have synced properly",{error:e})}const V=await l.handleMultiFileGitCommit(q,A,L,G,{operationType:"Replace lines",toolRecordId:k,successField:"successfulReplacements",logger:w,metrics:m,metricsPrefix:"replace_lines"},n),K=l.processMultiFileOperationResults(L,"successfulReplacements"),{successfulOperations:Y,failedOperations:J,totalSuccessfulChanges:Q,overallSuccess:Z,successfulFiles:X,failedFiles:ee}=K
2223
- try{await s.updateToolRecord(k,{metadata:{path:A.length>0?A[0].path:`document:${P[0]?.documentId}`,status:Z?"completed":"failed",error:Z?void 0:`${J} operations failed`,totalOperations:L.length,successfulFiles:X,failedFiles:ee,operations:z,totalSuccessfulReplacements:Q,totalFailedReplacements:H,totalLinesReplaced:U,totalLinesAdded:W,operationsWithChanges:G,processingTime:Date.now()-b,userComment:_,...A.length>0&&V.success&&V.commitHash&&{commitHash:V.commitHash,previousCommitHash:V.previousCommitHash||void 0}},note:Z?`Line replacement completed: ${Y}/${L.length} operations successful${A.length>0?" (committed to git)":""}`:`Line replacement partially failed: ${J}/${L.length} operations failed`})}catch(e){w.warn("Failed to update tool record",{recordError:e})}let te="## Line Replacement Results\n\n"
2225
+ try{await s.updateToolRecord(k,{metadata:{path:A.length>0?A[0].path:`document:${j[0]?.documentId}`,status:Z?"completed":"failed",error:Z?void 0:`${J} operations failed`,totalOperations:L.length,successfulFiles:X,failedFiles:ee,operations:z,totalSuccessfulReplacements:Q,totalFailedReplacements:H,totalLinesReplaced:U,totalLinesAdded:W,operationsWithChanges:G,processingTime:Date.now()-b,userComment:_,...A.length>0&&V.success&&V.commitHash&&{commitHash:V.commitHash,previousCommitHash:V.previousCommitHash||void 0}},note:Z?`Line replacement completed: ${Y}/${L.length} operations successful${A.length>0?" (committed to git)":""}`:`Line replacement partially failed: ${J}/${L.length} operations failed`})}catch(e){w.warn("Failed to update tool record",{recordError:e})}let te="## Line Replacement Results\n\n"
2224
2226
  if(n.workspaceManager){const e=n.workspaceManager.getCurrentContext(n.currentSessionId)
2225
2227
  e.permanentBranch||(te+=`**Branch:** \`${e.branchName}\`\n\n`)}if(te+="**Summary:**\n",te+=`- **Files processed:** ${Y+J}\n`,te+=`- **Successful operations:** ${Y}\n`,te+=`- **Failed operations:** ${J}\n`,te+=`- **Total replacements:** ${Q} successful, ${H} failed\n`,te+=`- **Total Lines Replaced:** ${U}\n`,W>0&&(te+=`- **Total Lines Added:** ${W}\n`),te+="\n",V.success&&V.commitHash&&(te+="**Git Commit:**\n",te+=`- **Commit Hash:** ${V.commitHash.substring(0,8)}\n`,te+=`- **Files Committed:** ${V.filesCommitted.length}\n`,V.previousCommitHash&&(te+=`- **Previous Commit:** ${V.previousCommitHash.substring(0,8)}\n`),te+="\n"),1===L.length){const e=L[0]
2226
2228
  if(te+=`**Operation:** ${e.success?"\u2705 Success":"\u274c Failed"}\n`,"file"===e.type?te+=`**File:** ${e.path}\n`:(te+=`**Document:** ${e.documentId}`,e.filename&&(te+=` (${e.filename})`),te+="\n"),e.error?te+=`**Error:** ${e.error}\n`:(te+=`**Replacements:** ${e.successfulReplacements} successful`,e.failedReplacements>0&&(te+=`, ${e.failedReplacements} failed`),te+="\n",te+=`**Lines Replaced:** ${e.totalLinesReplaced}\n`,e.totalLinesAdded>0&&(te+=`**Lines Added:** ${e.totalLinesAdded}\n`)),e.replacements.some(e=>!e.success)){te+="**Failed Replacement Details:**\n"
2227
2229
  for(const t of e.replacements.filter(e=>!e.success))te+=`- Replace ${"number"==typeof t.lines?`line ${t.lines}`:Array.isArray(t.lines)?`lines [${t.lines.join(", ")}]`:`lines ${t.lines.start}-${t.lines.end}`}: ${t.error}\n`}}else{te+="**Summary:**\n",te+=`- **Total Operations:** ${L.length}\n`,te+=`- **Successful:** ${Y}\n`,te+=`- **Failed:** ${J}\n`,te+=`- **Total Replacements:** ${Q} successful, ${H} failed\n`,te+=`- **Total Lines Replaced:** ${U}\n`,W>0&&(te+=`- **Total Lines Added:** ${W}\n`),te+="\n",te+="**Detailed Results:**\n\n"
2228
2230
  for(const e of L){if("file"===e.type?te+=`### File: ${e.path}\n`:(te+=`### Document: ${e.documentId}`,e.filename&&(te+=` (${e.filename})`),te+="\n"),te+=`- **Status:** ${e.success?"\u2705 Success":"\u274c Failed"}\n`,e.error&&(te+=`- **Error:** ${e.error}\n`),te+=`- **Replacements:** ${e.successfulReplacements} successful`,e.failedReplacements>0&&(te+=`, ${e.failedReplacements} failed`),te+="\n",te+=`- **Lines Replaced:** ${e.totalLinesReplaced}\n`,e.totalLinesAdded>0&&(te+=`- **Lines Added:** ${e.totalLinesAdded}\n`),e.replacements.some(e=>!e.success)){te+="- **Failed Replacement Details:**\n"
2229
- for(const t of e.replacements.filter(e=>!e.success))te+=` - Replace ${"number"==typeof t.lines?`line ${t.lines}`:Array.isArray(t.lines)?`lines [${t.lines.join(", ")}]`:`lines ${t.lines.start}-${t.lines.end}`}: ${t.error}\n`}te+="\n"}}P.length>0&&(te+="\u{1f4c4} **Document Changes:** Modified documents have been automatically synced back to the tracking system.\n\n")
2231
+ for(const t of e.replacements.filter(e=>!e.success))te+=` - Replace ${"number"==typeof t.lines?`line ${t.lines}`:Array.isArray(t.lines)?`lines [${t.lines.join(", ")}]`:`lines ${t.lines.start}-${t.lines.end}`}: ${t.error}\n`}te+="\n"}}j.length>0&&(te+="\u{1f4c4} **Document Changes:** Modified documents have been automatically synced back to the tracking system.\n\n")
2230
2232
  const re=Date.now()-b
2231
2233
  return w.info("Replace lines operation completed",{duration:re,success:Z,totalOperations:L.length,successfulOperations:Y,failedOperations:J}),m.incrementCounter("replace_lines_total",1,{success:Z}),{content:[{type:"text",text:te}],isError:!Z}}catch(t){const r=Date.now()-b
2232
2234
  if(w.error("Replace lines operation failed",{error:t instanceof Error?t.stack:String(t),duration:r,phase:I}),k)try{await s.updateToolRecord(k,{metadata:{path:e?.operations?.[0]?.path||e?.operations?.[0]?.documentId,status:"failed",error:(0,f.getErrorMessage)(t),phase:I,duration:r,userComment:e?.comment},note:`Line replacement failed: ${(0,f.getErrorMessage)(t)}`})}catch(e){}return m.incrementCounter("replace_lines_errors",1,{phase:I}),{content:[{type:"text",text:`\u274c **Replace Lines Failed:** ${(0,f.getErrorMessage)(t)}`}],isError:!0}}}(...e))}
@@ -2266,18 +2268,18 @@ for(const e of T)A.push({type:"document",documentId:e.documentId,replacements:e.
2266
2268
  if(A.length>0&&r.apiClient){const e=A.map(e=>e.documentId)
2267
2269
  try{await(0,f.ensureDocumentsNotLocked)(e,r.apiClient,y,c,"replace-strings-documents")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2268
2270
  throw e}}k=d.FileOperationPhase.TASK_VALIDATION,c.incrementCounter("replace_strings_phase",1,{phase:k})
2269
- const P=R.length>0?R[0].path:"document-operation",j=await d.validateTaskId(C,P,o,y,c,I.metricsPrefix),O=j?.requestId
2271
+ const j=R.length>0?R[0].path:"document-operation",P=await d.validateTaskId(C,j,o,y,c,I.metricsPrefix),O=P?.requestId
2270
2272
  let M=null
2271
2273
  R.length>0&&O&&(M=await d.validateWorkItemStates(C,R[0].path,o,i,r,y,c,I.metricsPrefix))
2272
2274
  let D={taskPromoted:!1,requestPromoted:!1}
2273
- R.length>0&&O&&M&&(D=await d.autoPromoteTaskStatus(C,j.status,O,M.request?.status,R[0].path,o,i,y,c,I.metricsPrefix),D.taskPromoted&&y.info("Auto-promoted task to in_progress for replace-strings operation",{taskId:C,requestId:O,previousStatus:j.status,newStatus:D.newTaskStatus,triggeringOperation:"replace-strings"}))
2275
+ R.length>0&&O&&M&&(D=await d.autoPromoteTaskStatus(C,P.status,O,M.request?.status,R[0].path,o,i,y,c,I.metricsPrefix),D.taskPromoted&&y.info("Auto-promoted task to in_progress for replace-strings operation",{taskId:C,requestId:O,previousStatus:P.status,newStatus:D.newTaskStatus,triggeringOperation:"replace-strings"}))
2274
2276
  const F=await d.ensureCorrectWorkspaceContext({taskPromoted:D.taskPromoted,requestId:O,context:r,operation:"replace-strings",logger:y,metrics:c,metricsPrefix:I.metricsPrefix})
2275
2277
  if(!F.success)throw new Error(F.error)
2276
2278
  if(R.length>0){y.debug("Re-validating file paths with correct workspace context",{operationCount:R.length,workspaceBasePath:r.workspaceManager?.getCurrentContext(r.currentSessionId).basePath})
2277
2279
  for(let e=0;e<R.length;e++){const t=R[e],n=q[e],{normalizedPath:o,fullPath:s}=d.validateAndNormalizePath(n.path,r)
2278
2280
  R[e]={...t,path:o,fullPath:s}}}if(A.length>0&&O)try{await(0,h.validateRequestStatusForDocumentOperation)(O,i,y,c,"replace-strings-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2279
2281
  throw e}k=d.FileOperationPhase.RECORD_CREATION,c.incrementCounter("replace_strings_phase",1,{phase:k})
2280
- const N=[...R.map(e=>({type:"file",path:e.path,replacements:e.replacements,mode:e.mode})),...A.map(e=>({type:"document",documentId:e.documentId,replacements:e.replacements,mode:e.mode}))],{toolRecordId:z}=await d.createFileOperationRecords(C,O,r.projectId,I.recordType,P,{operationCount:x.length,fileOperations:R.length,documentOperations:A.length,operations:N,userComment:S},o,s,y,c,I.metricsPrefix,g)
2282
+ const N=[...R.map(e=>({type:"file",path:e.path,replacements:e.replacements,mode:e.mode})),...A.map(e=>({type:"document",documentId:e.documentId,replacements:e.replacements,mode:e.mode}))],{toolRecordId:z}=await d.createFileOperationRecords(C,O,r.projectId,I.recordType,j,{operationCount:x.length,fileOperations:R.length,documentOperations:A.length,operations:N,userComment:S},o,s,y,c,I.metricsPrefix,g)
2281
2283
  if(b=z,v=z,k=I.fileOperationPhase,c.incrementCounter("replace_strings_phase",1,{phase:k}),R.length>0&&r.git)try{y.debug("[REPLACE-STRINGS] Checking for user changes before replace operations")
2282
2284
  const e=await(0,p.commitUserChangesBeforeToolOperation)(r.git,"replace-strings",{requestId:O,taskId:C,workspaceManager:r.workspaceManager},y,c)
2283
2285
  e.userChangesCommitted&&(y.debug("[REPLACE-STRINGS] User changes committed before replace operations",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),y.info("User changes committed before replace-strings operation",{taskId:C,fileOperationsCount:R.length,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){y.debug("[REPLACE-STRINGS] Pre-tool commit failed, continuing with replacements",{error:e instanceof Error?e.message:String(e)}),y.warn("Pre-tool user changes commit failed, continuing with replace operation",{taskId:C,fileOperationsCount:R.length,error:e instanceof Error?e.message:String(e)})}y.debug("[REPLACE-STRINGS] Proceeding with file operations",{fileCount:R.length})
@@ -2348,14 +2350,14 @@ _=i,S=`${t} @ ${"base"===e.revision?`base (${n.slice(0,7)})`:n.slice(0,12)}`,E=b
2348
2350
  if(!e)return o(`\u274c File not found: ${S}`)
2349
2351
  const t=await(0,y.renderViaActionServer)(e,C,"pdf")
2350
2352
  if(!t.ok){const e=(0,y.renderProblemText)(t,`Cannot show ${S} yet`,"read_files gives its text now.")
2351
- return t.preparing?{content:[{type:"text",text:e}]}:o(`\u274c ${e}`)}_=t.bytes,E="application/pdf",S=`${S} (rendered to PDF)`}if(!_)try{if(!(await l.stat(T)).isFile())return o(`\u274c Not a file: ${S}`)}catch{return o(`\u274c ${I?"Asset":"File"} not found: ${S}`)}const A=_?"image/svg+xml"===E?"svg":"":d.extname(T).toLowerCase().slice(1),P=E??b[A]
2352
- if(!P)return o(`\u274c view_asset shows images (png, jpg, gif, webp, svg), PDFs and office files, not .${A}. For text, use read_files.`)
2353
+ return t.preparing?{content:[{type:"text",text:e}]}:o(`\u274c ${e}`)}_=t.bytes,E="application/pdf",S=`${S} (rendered to PDF)`}if(!_)try{if(!(await l.stat(T)).isFile())return o(`\u274c Not a file: ${S}`)}catch{return o(`\u274c ${I?"Asset":"File"} not found: ${S}`)}const A=_?"image/svg+xml"===E?"svg":"":d.extname(T).toLowerCase().slice(1),j=E??b[A]
2354
+ if(!j)return o(`\u274c view_asset shows images (png, jpg, gif, webp, svg), PDFs and office files, not .${A}. For text, use read_files.`)
2353
2355
  if("svg"===A)return{content:[{type:"text",text:`**Asset: ${S}**\n\n\`\`\`svg\n${_?_.toString("utf-8"):await l.readFile(T,"utf-8")}\n\`\`\``}]}
2354
- const j=_??await l.readFile(T)
2355
- if("application/pdf"===P){let t
2356
- try{t=await(0,f.preparePdfView)(new Uint8Array(j),$)}catch(e){return o(`\u274c Cannot show ${S}: ${(0,u.getErrorMessage)(e)}.`)}if(t.bytes.byteLength>f.MAX_PDF_BYTES_PER_VIEW)return o(`\u274c Those pages of ${S} come to ${(t.bytes.byteLength/1048576).toFixed(1)} MB, over the ${f.MAX_PDF_BYTES_PER_VIEW/1048576} MB per view. Ask for fewer pages.`)
2356
+ const P=_??await l.readFile(T)
2357
+ if("application/pdf"===j){let t
2358
+ try{t=await(0,f.preparePdfView)(new Uint8Array(P),$)}catch(e){return o(`\u274c Cannot show ${S}: ${(0,u.getErrorMessage)(e)}.`)}if(t.bytes.byteLength>f.MAX_PDF_BYTES_PER_VIEW)return o(`\u274c Those pages of ${S} come to ${(t.bytes.byteLength/1048576).toFixed(1)} MB, over the ${f.MAX_PDF_BYTES_PER_VIEW/1048576} MB per view. Ask for fewer pages.`)
2357
2359
  const r=t.pages.length===t.totalPages?`all ${t.totalPages} pages`:`pages ${(0,f.rangeLabel)(t.pages)} of ${t.totalPages}`
2358
- return await R(P),k.info("PDF viewed",{path:S,pages:(0,f.rangeLabel)(t.pages),totalPages:t.totalPages,bytes:t.bytes.byteLength}),{content:[{type:"text",text:`**PDF: ${S}** (${r}, ${(t.bytes.byteLength/1024).toFixed(0)} KB). The pages are attached; read them as they appear.`},{type:"resource",resource:{uri:`${e.result?`result:${e.result}`:`file:///${(x??S).replace(/^\/+/,"")}${e.revision?`?revision=${encodeURIComponent(e.revision)}`:""}`}${t.pages.length===t.totalPages?"":`#pages=${(0,f.rangeLabel)(t.pages)}`}`,mimeType:P,blob:Buffer.from(t.bytes).toString("base64")}}]}}return await R(P),k.info("Asset viewed",{path:S,size:j.length}),{content:[{type:"text",text:`**Asset: ${S}** (${(j.length/1024).toFixed(1)} KB)`},{type:"image",data:j.toString("base64"),mimeType:P}]}}catch(e){return k.error("Failed to view asset",{error:(0,u.getErrorMessage)(e)}),o(`\u274c **Failed to view asset:** ${(0,u.getErrorMessage)(e)}`)}}
2360
+ return await R(j),k.info("PDF viewed",{path:S,pages:(0,f.rangeLabel)(t.pages),totalPages:t.totalPages,bytes:t.bytes.byteLength}),{content:[{type:"text",text:`**PDF: ${S}** (${r}, ${(t.bytes.byteLength/1024).toFixed(0)} KB). The pages are attached; read them as they appear.`},{type:"resource",resource:{uri:`${e.result?`result:${e.result}`:`file:///${(x??S).replace(/^\/+/,"")}${e.revision?`?revision=${encodeURIComponent(e.revision)}`:""}`}${t.pages.length===t.totalPages?"":`#pages=${(0,f.rangeLabel)(t.pages)}`}`,mimeType:j,blob:Buffer.from(t.bytes).toString("base64")}}]}}return await R(j),k.info("Asset viewed",{path:S,size:P.length}),{content:[{type:"text",text:`**Asset: ${S}** (${(P.length/1024).toFixed(1)} KB)`},{type:"image",data:P.toString("base64"),mimeType:j}]}}catch(e){return k.error("Failed to view asset",{error:(0,u.getErrorMessage)(e)}),o(`\u274c **Failed to view asset:** ${(0,u.getErrorMessage)(e)}`)}}
2359
2361
  const l=c(t(91943)),d=c(t(16928)),u=t(58824),h=t(14139),p=c(t(85967)),f=t(82926),m=t(50441),g=t(12661),y=t(73317),w=t(86605),b={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",pdf:"application/pdf"}},9030(e,exports,t){exports.def=void 0
2360
2362
  const r=t(76183),n=t(14079)
2361
2363
  exports.def={name:"write_file",description:"Write a file (path) or a tracked document (documentId). A file write needs a comment, creates or overwrites the file and commits it under your active task. append:true adds to the end. content is a string or an array of lines (joined with \\n); prefer the array for code, JSON, TOML or YAML, which avoids escaping mistakes. fromResult instead of content writes a recorded result's bytes unchanged: how a file made in a sealed box lands in the repository. Content starting with #! is written executable. To make an existing script executable, write it again with its same content.",schema:r.WriteFileSchema,annotations:{title:"Write File/Document",readOnlyHint:!1,destructiveHint:!0,idempotentHint:!1},createsRecords:!0,handler:(e,t)=>(0,n.handleWriteFile)(e,t.context,t.apiClient.getFileClient(),t.apiClient.getTaskClient(),t.apiClient.getToolRecordClient(),t.apiClient.getRequestClient(),t.logger,t.metrics,t.mcpServer)}},14079(e,exports,t){var r,n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
@@ -2370,18 +2372,18 @@ Object.defineProperty(exports,"__esModule",{value:!0}),exports.handleWriteFile=f
2370
2372
  let _,E,C=d.FileOperationPhase.VALIDATION
2371
2373
  const q={toolName:"write_file",operationName:"write",fileOperationPhase:d.FileOperationPhase.FILE_WRITE,recordType:"write-file",metricsPrefix:"write_file",successMessage:"Successfully wrote content",failureMessage:"Failed to write content"}
2372
2374
  try{const n=e
2373
- let{path:T,documentId:R,content:A,format:P,append:j,comment:O,fromResult:M}=n
2375
+ let{path:T,documentId:R,content:A,format:j,append:P,comment:O,fromResult:M}=n
2374
2376
  Array.isArray(A)&&(A=A.join("\n"))
2375
2377
  const{enforceActiveTask:D}=await Promise.resolve().then(()=>t(43451)),F=await D(r,o,w,e.taskId)
2376
2378
  if("errorResult"in F)return F.errorResult
2377
2379
  const{taskId:N}=F
2378
2380
  let z,B
2379
2381
  if(void 0!==M){if(!T)throw new u.ValidationError("`fromResult` writes a file: pass it with `path`, not `documentId`.")
2380
- if(void 0!==A||j)throw new u.ValidationError("`fromResult` takes the place of `content`: pass one or the other, without `append`.")
2382
+ if(void 0!==A||P)throw new u.ValidationError("`fromResult` takes the place of `content`: pass one or the other, without `append`.")
2381
2383
  const e=await(0,y.readResultBytes)(r.mainBasePath,M,20971520)
2382
2384
  if(!e.ok)throw new u.ValidationError(e.tooLarge?`${e.message} That is bulk, which stays in the results store: use results({ operation: "pin" }) to carry it on the branch.`:e.message)
2383
2385
  z=e.bytes,B=e.address}const L=z?z.length:"string"==typeof A?A.length:JSON.stringify(A??"").length,H=!!R,U=!!T
2384
- $.info("Writing content to "+(H?"document":"file"),{taskId:N,filePath:U?T:void 0,documentId:H?R:void 0,contentLength:L,fromResult:B,format:P,append:j,comment:O})
2386
+ $.info("Writing content to "+(H?"document":"file"),{taskId:N,filePath:U?T:void 0,documentId:H?R:void 0,contentLength:L,fromResult:B,format:j,append:P,comment:O})
2385
2387
  let W,G,V,K="",Y=!1,J=!1
2386
2388
  const Q=U?T:void 0
2387
2389
  if(H){if(!r.documentFileManager)throw new Error("Document file manager not available")
@@ -2399,28 +2401,28 @@ if(ne.switched&&$.info("Workspace context successfully established",{requestId:e
2399
2401
  W=e.normalizedPath,G=e.fullPath,K=G
2400
2402
  try{await c.default.access(G),J=!0}catch{J=!1,Y=!0}const t=(0,g.projectMapCreateProblem)(W,J)
2401
2403
  if(t)throw new u.ValidationError(t)
2402
- if(J&&!j){const e=r.workspaceManager?.getCurrentContext(r.currentSessionId)
2404
+ if(J&&!P){const e=r.workspaceManager?.getCurrentContext(r.currentSessionId)
2403
2405
  if(e?.requestId&&e.basePath){const t=await(0,b.staleWriteProblem)({sessionId:r.currentSessionId,worktree:e.basePath,fullPath:G,relPath:W,defaultBranch:await(0,v.resolveDefaultBranch)(r.basePath)})
2404
2406
  if(t)throw new u.ValidationError(`${W} was not written: ${t}`)}}$.debug("Path validated with correct workspace context",{rawPath:Q,normalizedPath:W,fullPath:G,workspaceBasePath:r.workspaceManager?.getCurrentContext(r.currentSessionId).basePath})}if(H&&ee)try{await(0,h.validateRequestStatusForDocumentOperation)(ee,i,$,k,"write_file-document")}catch(e){if(e instanceof u.ValidationError)return{content:[{type:"text",text:e.message}],isError:!0}
2405
2407
  throw e}C=d.FileOperationPhase.RECORD_CREATION,k.incrementCounter("write_file_phase",1,{phase:C})
2406
- const{toolRecordId:oe}=await d.createFileOperationRecords(N,ee,r.projectId,q.recordType,Z,{operationType:H?"document":"file",documentId:H?R:void 0,documentFilename:V,filePath:U?W:void 0,contentLength:L,...B?{fromResult:B}:{},format:P||"text",append:j||!1,wasFileCreated:!J,userComment:O},o,s,$,k,q.metricsPrefix,I)
2408
+ const{toolRecordId:oe}=await d.createFileOperationRecords(N,ee,r.projectId,q.recordType,Z,{operationType:H?"document":"file",documentId:H?R:void 0,documentFilename:V,filePath:U?W:void 0,contentLength:L,...B?{fromResult:B}:{},format:j||"text",append:P||!1,wasFileCreated:!J,userComment:O},o,s,$,k,q.metricsPrefix,I)
2407
2409
  _=oe,E=oe,C=q.fileOperationPhase,k.incrementCounter("write_file_phase",1,{phase:C})
2408
2410
  let se=""
2409
- if(z);else if("json"===P)if("string"==typeof A)try{JSON.parse(A),se=A}catch(e){throw new u.ValidationError("Content is not valid JSON")}else se=JSON.stringify(A,null,2)
2411
+ if(z);else if("json"===j)if("string"==typeof A)try{JSON.parse(A),se=A}catch(e){throw new u.ValidationError("Content is not valid JSON")}else se=JSON.stringify(A,null,2)
2410
2412
  else se="string"==typeof A?A:JSON.stringify(A,null,2)
2411
2413
  let ie=se
2412
2414
  if(U&&r.git)try{$.debug("[WRITE-FILE] Checking for user changes before write operation")
2413
2415
  const e=await(0,p.commitUserChangesBeforeToolOperation)(r.git,"write_file",{requestId:r.workspaceManager?.getCurrentContext(r.currentSessionId)?.requestId,taskId:N},$,k)
2414
2416
  e.userChangesCommitted&&($.debug("[WRITE-FILE] User changes committed before write operation",{commitHash:e.commitHash?.substring(0,8),filesCommitted:e.filesCommitted}),$.info("User changes committed before write-file operation",{taskId:N,path:W,userCommitHash:e.commitHash?.substring(0,8),userFilesCommitted:e.filesCommitted}))}catch(e){$.debug("[WRITE-FILE] Pre-tool commit failed, continuing with write",{error:e instanceof Error?e.message:String(e)}),$.warn("Pre-tool user changes commit failed, continuing with write operation",{taskId:N,path:W,error:e instanceof Error?e.message:String(e)})}if(!K)throw new Error("Target path not properly initialized")
2415
- if($.debug("[WRITE-FILE] Proceeding with file write operation",{targetPath:K}),j&&J)try{ie=await c.default.readFile(K,"utf8")+se}catch(e){$.warn("Failed to read existing content for append",{error:e})}const ae=a.default.dirname(K)
2417
+ if($.debug("[WRITE-FILE] Proceeding with file write operation",{targetPath:K}),P&&J)try{ie=await c.default.readFile(K,"utf8")+se}catch(e){$.warn("Failed to read existing content for append",{error:e})}const ae=a.default.dirname(K)
2416
2418
  await c.default.mkdir(ae,{recursive:!0}),z?await c.default.writeFile(K,z):await c.default.writeFile(K,ie,"utf8")
2417
- const ce=z?z.length:ie.length,le=!(!U||z||j)&&await(0,f.markExecutableIfShebang)(K,ie)
2418
- if($.info("Content written successfully",{path:U?W:`document:${R}`,finalLength:ce,append:j,wasCreated:Y}),H){r.documentFileManager.markForSync(R)
2419
+ const ce=z?z.length:ie.length,le=!(!U||z||P)&&await(0,f.markExecutableIfShebang)(K,ie)
2420
+ if($.info("Content written successfully",{path:U?W:`document:${R}`,finalLength:ce,append:P,wasCreated:Y}),H){r.documentFileManager.markForSync(R)
2419
2421
  try{await r.documentFileManager.syncDocument(R),$.info("Document synced successfully",{documentId:R})}catch(e){$.warn("Failed to sync document immediately",{documentId:R,error:e})}}let de,ue,he=null,pe=null,fe=!1
2420
2422
  if(U){if(C=d.FileOperationPhase.GIT_COMMIT,k.incrementCounter("write_file_phase",1,{phase:C}),r.workspaceManager){const e=r.workspaceManager.getCurrentContext(r.currentSessionId)
2421
- ue=e.branchName,fe=e.permanentBranch,$.debug("Retrieved branch name from workspace manager",{branchName:ue,requestId:e.requestId,mode:e.mode,isMainBranch:e.isMainBranch})}try{const e=`${Y?"Create":j?"Append to":"Update"} ${W} (${E})`,t=await d.commitToGit(N,W,E,E,e,r,$,k,q.metricsPrefix)
2422
- de=t.commitHash,pe=t.previousCommitHash,$.info("Changes committed to git via shared utility",{path:W,commitMessage:e,commitHash:de?.substring(0,8),previousCommitHash:pe?.substring(0,8),branchName:ue,toolRecordId:E})}catch(e){$.warn("Git operations failed via shared utility",{error:e}),he=(0,m.getErrorMessage)(e)}}try{await s.updateToolRecord(E,{metadata:{path:U?W:`document:${R}`,status:"completed",finalContentLength:ce,...B?{fromResult:B}:{},wasFileCreated:Y,wasAppended:j&&J,operationType:H?"document":"file",processingTime:Date.now()-S,userComment:O,...U&&de&&{commitHash:de,previousCommitHash:pe||void 0},...U&&he?{commitFailed:!0,commitFailedReason:he}:null},note:H?"Write operation completed successfully (document synced)":he?"Write landed on disk but the git commit FAILED -- the change is uncommitted":"Write operation completed successfully (committed to git)"})}catch(e){$.warn("Failed to update tool record",{recordError:e})}if(U&&G&&de){const e=r.workspaceManager?.getCurrentContext(r.currentSessionId)
2423
- e?.requestId&&await(0,b.noteFileSeen)(r.currentSessionId,e.basePath,G)}let me=`**${Y?"Created":j?"Appended to":"Updated"} ${H?`document ${R}${V?` (${V})`:""}`:`file ${W}`}**\n`
2423
+ ue=e.branchName,fe=e.permanentBranch,$.debug("Retrieved branch name from workspace manager",{branchName:ue,requestId:e.requestId,mode:e.mode,isMainBranch:e.isMainBranch})}try{const e=`${Y?"Create":P?"Append to":"Update"} ${W} (${E})`,t=await d.commitToGit(N,W,E,E,e,r,$,k,q.metricsPrefix)
2424
+ de=t.commitHash,pe=t.previousCommitHash,$.info("Changes committed to git via shared utility",{path:W,commitMessage:e,commitHash:de?.substring(0,8),previousCommitHash:pe?.substring(0,8),branchName:ue,toolRecordId:E})}catch(e){$.warn("Git operations failed via shared utility",{error:e}),he=(0,m.getErrorMessage)(e)}}try{await s.updateToolRecord(E,{metadata:{path:U?W:`document:${R}`,status:"completed",finalContentLength:ce,...B?{fromResult:B}:{},wasFileCreated:Y,wasAppended:P&&J,operationType:H?"document":"file",processingTime:Date.now()-S,userComment:O,...U&&de&&{commitHash:de,previousCommitHash:pe||void 0},...U&&he?{commitFailed:!0,commitFailedReason:he}:null},note:H?"Write operation completed successfully (document synced)":he?"Write landed on disk but the git commit FAILED -- the change is uncommitted":"Write operation completed successfully (committed to git)"})}catch(e){$.warn("Failed to update tool record",{recordError:e})}if(U&&G&&de){const e=r.workspaceManager?.getCurrentContext(r.currentSessionId)
2425
+ e?.requestId&&await(0,b.noteFileSeen)(r.currentSessionId,e.basePath,G)}let me=`**${Y?"Created":P?"Appended to":"Updated"} ${H?`document ${R}${V?` (${V})`:""}`:`file ${W}`}**\n`
2424
2426
  me+=B?`**From result:** ${B.slice(0,12)} (${ce.toLocaleString()} bytes, unchanged)\n`:`**Content Length:** ${ie.length} characters\n`,U&&ue&&(fe||(me+=`**Branch:** ${ue}\n`)),le&&(me+="**Mode:** executable (100755), because it starts with #!\n"),U&&he&&(me+=`\u26a0\ufe0f **NOT COMMITTED:** the file is written on disk but the git commit failed (${he}). Do not complete this work until the change is committed.\n`),U&&de&&(me+=`**Commit Hash:** ${de.substring(0,8)}\n`,pe&&(me+=`**Previous Commit:** ${pe.substring(0,8)}\n`)),H&&(me+=`\n**Document Update:** The document content has been updated and synced back to the tracking system. You can continue editing using other file modification tools with documentId \`${R}\`.`)
2425
2427
  const ge=Date.now()
2426
2428
  $.info("Write operation completed successfully",{duration:ge-S,path:U?W:`document:${R}`,contentLength:ce,wasCreated:Y}),x({tool:"write_file",success:!0}),k.incrementCounter("write_file_total",1,{success:!0})
@@ -2629,11 +2631,11 @@ const w=t.workspaceManager?.getCurrentContext(t.currentSessionId)?.basePath||t.b
2629
2631
  let I,$,x
2630
2632
  try{$=(await b.raw(["rev-parse",k])).trim(),x=(await b.raw(["rev-parse",v])).trim(),I=(await b.raw(["merge-base",k,v])).trim()}catch(e){return f({success:!1,reason:"no_refs"}),n(`Could not resolve ${v} against ${k}: ${(0,a.getErrorMessage)(e)}`)}const S=g?["--",g]:[],_={requestId:u,branch:v,defaultBranch:k,mergeBaseSha:I,mainHeadSha:$,branchTipSha:x}
2631
2633
  if(I===$)return f({success:!0}),h.incrementCounter("merge_preview_total",1,{outcome:"up_to_date"}),r({..._,upToDate:!0,mainAheadBy:0,conflicts:null,overlap:[],summary:`${k} has not moved since this branch forked. What you have built is what would land; nothing to reconcile.`})
2632
- const E=await b.raw(["rev-list","--count",`${I}..${$}`]),C=Number(E.trim())||0,q=await o(b,`${I}..${x}`,S),T=await o(b,`${I}..${$}`,S),R=new Set(q.map(e=>e.path)),A=T.filter(e=>R.has(e.path)).map(e=>e.path),P=await(0,c.buildProspectiveMergeCommit)(w,{defaultBranch:k,branchName:v,requestId:u,requestTitle:y.title,gitBinary:t.gitBinary})
2633
- if(!P.ok&&"conflicts"===P.reason)return f({success:!0}),h.incrementCounter("merge_preview_total",1,{outcome:"conflicts"}),r({..._,upToDate:!1,mainAheadBy:C,conflicts:{summary:P.conflictSummary},overlap:A,yourFiles:q.map(e=>e.path),incomingFiles:T,summary:`${k} moved by ${C} commit(s) and the merge CONFLICTS. Keep working: the pipeline routes conflicts into their own lane and delivers them to you as markers in the files, which you resolve by editing them. You never run git yourself. This is a heads-up, not a task, and NOT a blocker to report: finish your change and complete the request; the conflicted merge comes back to you as markers. Reporting it to your parent registers no wait and moves nothing.`})
2634
- if(!P.ok)return f({success:!1,reason:"build_failed"}),n(`Could not build the prospective merge for ${u}: ${P.error}`)
2635
- const j=await o(b,`${x}..${P.mergeCommitSha}`,S),O={..._,upToDate:!1,mainAheadBy:C,conflicts:null,prospectiveMergeCommit:P.mergeCommitSha,treeSha:P.treeSha,overlap:A,yourFiles:q.map(e=>e.path),addedByMerge:j,summary:A.length?`${k} moved by ${C} commit(s) and the merge is CLEAN, but ${A.length} file(s) were changed by both: ${A.slice(0,8).join(", ")}${A.length>8?", ...":""}. Clean means no textual conflict, NOT that the combined behaviour is right: read those files as merged before you rely on your earlier check.`:`${k} moved by ${C} commit(s), the merge is CLEAN, and none of the files you changed were touched. Nothing to reconcile.`}
2636
- if("unified"===m){const e=await b.raw(["diff","-M50%",`${x}..${P.mergeCommitSha}`,...S]),t=e.length>d
2634
+ const E=await b.raw(["rev-list","--count",`${I}..${$}`]),C=Number(E.trim())||0,q=await o(b,`${I}..${x}`,S),T=await o(b,`${I}..${$}`,S),R=new Set(q.map(e=>e.path)),A=T.filter(e=>R.has(e.path)).map(e=>e.path),j=await(0,c.buildProspectiveMergeCommit)(w,{defaultBranch:k,branchName:v,requestId:u,requestTitle:y.title,gitBinary:t.gitBinary})
2635
+ if(!j.ok&&"conflicts"===j.reason)return f({success:!0}),h.incrementCounter("merge_preview_total",1,{outcome:"conflicts"}),r({..._,upToDate:!1,mainAheadBy:C,conflicts:{summary:j.conflictSummary},overlap:A,yourFiles:q.map(e=>e.path),incomingFiles:T,summary:`${k} moved by ${C} commit(s) and the merge CONFLICTS. Keep working: the pipeline routes conflicts into their own lane and delivers them to you as markers in the files, which you resolve by editing them. You never run git yourself. This is a heads-up, not a task, and NOT a blocker to report: finish your change and complete the request; the conflicted merge comes back to you as markers. Reporting it to your parent registers no wait and moves nothing.`})
2636
+ if(!j.ok)return f({success:!1,reason:"build_failed"}),n(`Could not build the prospective merge for ${u}: ${j.error}`)
2637
+ const P=await o(b,`${x}..${j.mergeCommitSha}`,S),O={..._,upToDate:!1,mainAheadBy:C,conflicts:null,prospectiveMergeCommit:j.mergeCommitSha,treeSha:j.treeSha,overlap:A,yourFiles:q.map(e=>e.path),addedByMerge:P,summary:A.length?`${k} moved by ${C} commit(s) and the merge is CLEAN, but ${A.length} file(s) were changed by both: ${A.slice(0,8).join(", ")}${A.length>8?", ...":""}. Clean means no textual conflict, NOT that the combined behaviour is right: read those files as merged before you rely on your earlier check.`:`${k} moved by ${C} commit(s), the merge is CLEAN, and none of the files you changed were touched. Nothing to reconcile.`}
2638
+ if("unified"===m){const e=await b.raw(["diff","-M50%",`${x}..${j.mergeCommitSha}`,...S]),t=e.length>d
2637
2639
  O.diff=t?e.slice(0,d):e,O.truncated=t,t&&(O.hint="Diff truncated at 500KB. Narrow with `path`, or start from `overlap`.")}return p.info("merge preview built",{requestId:u,mainAheadBy:C,overlap:A.length,clean:!0}),f({success:!0}),h.incrementCounter("merge_preview_total",1,{outcome:A.length?"overlap":"clean"}),r(O)}catch(e){return f({success:!1,reason:"error"}),p.error("merge_preview failed",{error:(0,a.getErrorMessage)(e)}),n(`merge_preview failed: ${(0,a.getErrorMessage)(e)}`)}}
2638
2640
  const s=t(83807),i=t(82272),a=t(58824),c=t(87192),l=t(52232),d=5e5},26473(e,exports,t){exports.def=void 0
2639
2641
  const r=t(76183),n=t(51020)
@@ -2675,15 +2677,15 @@ return r({baseSha:x,headSha:S,branch:I?null:$,...o.length?{changesInLongLines:o}
2675
2677
  for(const e of q.split("\n").filter(Boolean)){const t=e.split("\t")
2676
2678
  if(t.length<3)continue
2677
2679
  const[r,n,...o]=t,s=o[o.length-1],i="-"===r&&"-"===n
2678
- R.set(s,{additions:i?0:parseInt(r,10)||0,deletions:i?0:parseInt(n,10)||0,binary:i})}const A=[...R.entries()].filter(([e,t])=>t.binary&&(0,c.isTextDiffedDocument)(e)).map(([e])=>e),P=new Map
2680
+ R.set(s,{additions:i?0:parseInt(r,10)||0,deletions:i?0:parseInt(n,10)||0,binary:i})}const A=[...R.entries()].filter(([e,t])=>t.binary&&(0,c.isTextDiffedDocument)(e)).map(([e])=>e),j=new Map
2679
2681
  if(A.length&&(0,c.documentDiffGitArgs)().length)try{const e=await k.raw([...(0,c.documentDiffGitArgs)(),"diff","-M50%",`${x}..${S}`,"--",...A])
2680
- for(const[t,r]of(0,c.countPatchLines)(e))P.set(t,r)}catch{}for(const e of A){const t=P.get(e)
2681
- t&&R.set(e,{...t,binary:!1})}const j=[]
2682
+ for(const[t,r]of(0,c.countPatchLines)(e))j.set(t,r)}catch{}for(const e of A){const t=j.get(e)
2683
+ t&&R.set(e,{...t,binary:!1})}const P=[]
2682
2684
  for(const e of T.split("\n").filter(Boolean)){const t=e.split("\t"),r=t[0]
2683
2685
  if(r.startsWith("R")){const e=t[1],n=t[2],o=R.get(n)||{additions:0,deletions:0,binary:!1},s=parseInt(r.slice(1),10),i={path:n,status:"renamed",additions:o.additions,deletions:o.deletions,oldPath:e}
2684
- Number.isFinite(s)&&(i.similarity=s),o.binary&&(i.binary=!0),(0,c.isTextDiffedDocument)(n)&&(i.document=!0),j.push(i)}else{const e=t[1],n=R.get(e)||{additions:0,deletions:0,binary:!1},o={path:e,status:"A"===r?"added":"D"===r?"deleted":"modified",additions:n.additions,deletions:n.deletions}
2685
- n.binary&&(o.binary=!0),(0,c.isTextDiffedDocument)(e)&&(o.document=!0),j.push(o)}}for(const e of C)j.push({path:e.path,status:"modified",additions:e.additions,deletions:e.deletions,document:!0})
2686
- return j.sort((e,t)=>e.path.localeCompare(t.path)),m({success:!0}),p.incrementCounter("request_diff_total",1,{format:"summary"}),r({baseSha:x,headSha:S,branch:I?null:$,files:j})}catch(e){return f.error("request_diff failed",{error:e instanceof Error?e.stack:String(e)}),m({success:!1}),p.incrementCounter("request_diff_errors",1),n(`request_diff failed: ${(0,a.getErrorMessage)(e)}`)}}
2686
+ Number.isFinite(s)&&(i.similarity=s),o.binary&&(i.binary=!0),(0,c.isTextDiffedDocument)(n)&&(i.document=!0),P.push(i)}else{const e=t[1],n=R.get(e)||{additions:0,deletions:0,binary:!1},o={path:e,status:"A"===r?"added":"D"===r?"deleted":"modified",additions:n.additions,deletions:n.deletions}
2687
+ n.binary&&(o.binary=!0),(0,c.isTextDiffedDocument)(e)&&(o.document=!0),P.push(o)}}for(const e of C)P.push({path:e.path,status:"modified",additions:e.additions,deletions:e.deletions,document:!0})
2688
+ return P.sort((e,t)=>e.path.localeCompare(t.path)),m({success:!0}),p.incrementCounter("request_diff_total",1,{format:"summary"}),r({baseSha:x,headSha:S,branch:I?null:$,files:P})}catch(e){return f.error("request_diff failed",{error:e instanceof Error?e.stack:String(e)}),m({success:!1}),p.incrementCounter("request_diff_errors",1),n(`request_diff failed: ${(0,a.getErrorMessage)(e)}`)}}
2687
2689
  const o=t(83807),s=t(92873),i=t(82272),a=t(58824),c=t(61161),l=t(95040),d=t(52232),u=5e5},58317(e,exports,t){function r(e){const t=[]
2688
2690
  return"write-file"===e.type&&e.metadata?.path?t.push(e.metadata.path):"replace-in-files"===e.type&&e.metadata?.operations?e.metadata.operations.forEach(e=>{e.path&&t.push(e.path)}):c.PRECISION_EDIT_TYPES.includes(e.type)&&e.metadata?.operations?e.metadata.operations.forEach(e=>{e?.path&&"string"==typeof e.path&&t.push(e.path)}):"move-files"===e.type&&e.metadata?.successfulOperations?e.metadata.successfulOperations.forEach(e=>{e.destination&&t.push(e.destination)}):"delete-files"===e.type&&e.metadata?.paths?t.push(...e.metadata.paths):"manage-files"===e.type&&e.metadata?.operations&&e.metadata.operations.forEach(e=>{e.createDirectory?.path&&t.push(e.createDirectory.path),e.moveFiles?.moves&&e.moveFiles.moves.forEach(e=>{e.destination&&t.push(e.destination)}),e.deleteFiles?.targets&&e.deleteFiles.targets.forEach(e=>{e.path&&t.push(e.path)})}),[...new Set(t)]}function n(e){switch(e){case"write-file":return"\u{1f4dd} Write File"
2689
2691
  case"replace-in-files":return"\u{1f504} Replace in Files"
@@ -2759,8 +2761,8 @@ r.setProjectId(w)
2759
2761
  try{const T=await g.getTask(f)
2760
2762
  s.info("Raw task response data",{responseDataType:typeof T,isArray:Array.isArray(T),hasData:null!=T,properties:T&&"object"==typeof T?Object.keys(T):[]}),b=(0,l.extractDataFromResponse)(T,{logger:s,operationName:"getTask",defaultValue:{id:f,title:"Unknown Task",status:"unknown",description:"No description available"}}),s.info(`Found task: ${b.title}`)}catch(R){s.warn(`Could not fetch task information: ${(0,u.getErrorMessage)(R)}`),b={id:f,title:"Unknown Task",status:"unknown",description:"No description available"}}let v=[]
2761
2763
  try{const A=await y.getToolRecordsByTaskId(f)
2762
- if(s.info("Raw records response data",{responseDataType:typeof A,isArray:Array.isArray(A),hasData:null!=A,properties:A&&"object"==typeof A?Object.keys(A):[]}),v=(0,l.extractArrayFromResponse)(A,{logger:s,operationName:"searchRecords",defaultValue:[]}),v.length>0&&s.info("First record summary:",{id:v[0].id,type:v[0].type,hasMetadata:!!v[0].metadata,hasCommitHash:!!v[0].metadata?.commitHash}),s.info(`Extracted ${v.length} records for task ${f}`),v.length>0){const P={}
2763
- v.forEach(e=>{P[e.type]=(P[e.type]||0)+1}),s.info("Record type distribution:",P)}}catch(j){s.warn(`Error fetching records for task ${f}`,{error:(0,u.getErrorMessage)(j)}),v=[]}if(0===v.length)return p({success:!0,recordCount:0}),{content:[{type:"text",text:`No records found for task ${f}.`}]}
2764
+ if(s.info("Raw records response data",{responseDataType:typeof A,isArray:Array.isArray(A),hasData:null!=A,properties:A&&"object"==typeof A?Object.keys(A):[]}),v=(0,l.extractArrayFromResponse)(A,{logger:s,operationName:"searchRecords",defaultValue:[]}),v.length>0&&s.info("First record summary:",{id:v[0].id,type:v[0].type,hasMetadata:!!v[0].metadata,hasCommitHash:!!v[0].metadata?.commitHash}),s.info(`Extracted ${v.length} records for task ${f}`),v.length>0){const j={}
2765
+ v.forEach(e=>{j[e.type]=(j[e.type]||0)+1}),s.info("Record type distribution:",j)}}catch(P){s.warn(`Error fetching records for task ${f}`,{error:(0,u.getErrorMessage)(P)}),v=[]}if(0===v.length)return p({success:!0,recordCount:0}),{content:[{type:"text",text:`No records found for task ${f}.`}]}
2764
2766
  function k(e){const t=new Map,r=new Map,n=[]
2765
2767
  for(const o of e)if("move-file"===o.type&&o.metadata){const e=o.metadata.source||o.metadata.oldPath,s=o.metadata.destination||o.metadata.newPath
2766
2768
  if(e&&s){const i={source:e,destination:s,recordId:o.id,timestamp:o.createdAt,type:"move-file"}
@@ -2863,9 +2865,9 @@ let C=0,q=!1
2863
2865
  if(m){for(const qe of S.values())qe.hasDiff&&qe.diffText&&(C+=qe.diffText.split("\n").length)
2864
2866
  q=C>E,s.info(`Total diff size: ${C} lines (limit: ${E} lines)`),s.info(`Diffs ${q?"will be limited":"will be shown"} based on size`)}if(_+="## Summary\n",_+=`- **Files Modified**: ${x.size}\n`,_+=`- **Total File Operations**: ${$.length}\n`,_+="- **What's Shown**: For existing files, comparing state before task started with final state.\n",_+=" For files created during task, showing the entire file as created.\n",q?(_+=`- **Diff Display**: Limited (total diff size of ${C} lines exceeds limit of ${E} lines)\n`,_+=" Use file-history tool with individual files to see detailed changes\n\n"):_+=`- **Diff Display**: ${m?"Enabled":"Disabled"} (use showDiff=${!m} to ${m?"hide":"show"} diffs)\n\n`,I.allMoves.length>0){_+="## Move Operations\n\n",_+=`Detected ${I.allMoves.length} file move operation(s):\n\n`
2865
2867
  for(const Te of I.allMoves)_+=`- **${Te.source}** \u2192 **${Te.destination}**\n`,_+=` - Operation: ${Te.type}\n`,_+=` - Timestamp: ${new Date(Te.timestamp).toLocaleString()}\n`,_+=` - Record ID: ${Te.recordId}\n\n`}_+="## Modified Files\n\n"
2866
- for(const[Re,Ae]of S.entries()){const{normalizedPath:Pe,fullPath:je}=d.validateAndNormalizePath(Re,t)
2868
+ for(const[Re,Ae]of S.entries()){const{normalizedPath:je,fullPath:Pe}=d.validateAndNormalizePath(Re,t)
2867
2869
  let Oe=!1
2868
- try{await a.access(je),Oe=!0}catch{}_+=`### ${Re} ${Oe?"":"(Deleted)"}\n\n`
2870
+ try{await a.access(Pe),Oe=!0}catch{}_+=`### ${Re} ${Oe?"":"(Deleted)"}\n\n`
2869
2871
  const Me=new Date(Ae.firstChange.timestamp).toLocaleString(),De=new Date(Ae.lastChange.timestamp).toLocaleString()
2870
2872
  _+=`**First Change**: ${Me}\n`,_+=`**Last Change**: ${De}\n`,"pre-task"===Ae.firstChange.status&&Ae.firstChange.commitHash?_+=`**Pre-Task Commit**: ${Ae.firstChange.commitHash.substring(0,8)}\n`:Ae.firstChange.commitHash&&(_+=`**File Created During Task**: ${Ae.firstChange.commitHash.substring(0,8)}\n`),Ae.lastChange.commitHash&&(_+=`**Final Commit**: ${Ae.lastChange.commitHash.substring(0,8)}\n`)
2871
2873
  const Fe=I.sourceToMove.get(Re),Ne=I.destToMove.get(Re)
@@ -2930,8 +2932,8 @@ if(null!=e)for(var r=n(e),i=0;i<r.length;i++)"default"!==r[i]&&o(t,e,r[i])
2930
2932
  return s(t,e),t})
2931
2933
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.logSessionIdentity=void 0,exports.registerTools=function(e,n,o,s,i,g,R){const A=s.child({component:"tools"})
2932
2934
  A.info("Registering tools...")
2933
- let P=!1
2934
- const j=!!g,O=async()=>{if(!j)return!0
2935
+ let j=!1
2936
+ const P=!!g,O=async()=>{if(!P)return!0
2935
2937
  try{return await g.hasValidToken()}catch(e){return A.error("Error checking authentication status",{error:(0,d.getErrorMessage)(e)}),!1}},M=async()=>{const e=(0,l.areTestsRequiredForCompletion)(),t=await O()
2936
2938
  A.info(`Generating tools list with testsRequired=${e}, authenticated=${t}`)
2937
2939
  const r={testsRequired:e,authenticated:t}
@@ -2943,7 +2945,7 @@ E&&(0,y.logSessionIdentity)(r,"_meta-debug",{has_meta:!!x,sessionId:x?.sessionId
2943
2945
  const F=i.startTimer("tool_execution_time")
2944
2946
  Date.now()
2945
2947
  let N=Date.now()
2946
- if(g=(0,I.readRawArgs)(l),Date.now(),N=Date.now(),j){const e=await O()
2948
+ if(g=(0,I.readRawArgs)(l),Date.now(),N=Date.now(),P){const e=await O()
2947
2949
  if(Date.now(),!e)return A.warn("Unauthenticated tool call attempt",{tool:r}),{content:[{type:"text",text:"Authentication required. Please run 'alchemylab setup' to authenticate and configure your project."}],isError:!0}}const z=(0,w.getToolByName)(r)
2948
2950
  let B
2949
2951
  if(N=Date.now(),o?(o.setOptions({createRecords:z?.createsRecords??!1}),A.info(`Setting record creation for tool ${r}: ${z?.createsRecords??!1}`)):A.debug(`No API client available for tool ${r} (minimal mode)`),Date.now(),Date.now(),N=Date.now(),x?.sessionId){const e=x.sessionId,t=x.messageId,s=p.sessionIdentity.getIdentity()
@@ -2957,7 +2959,7 @@ if(!o)return
2957
2959
  const s=await fetch(`${o.replace(/\/$/,"")}/session/${encodeURIComponent(t)}`,{signal:AbortSignal.timeout(3e3)})
2958
2960
  if(!s.ok)return void q.set(t,null)
2959
2961
  const i=await s.json(),a="string"==typeof i?.path?.cwd?i.path.cwd:"",c=e.mainBasePath||e.basePath
2960
- a&&((0,m.isInWorkDir)(c,"setup-worktrees",a)||(0,m.isInWorkDir)(c,"test-worktrees",a))?(q.set(t,a),e.workspaceManager.setSessionWorktree(t,a)):q.set(t,null)}catch{}}(n,e,p.sessionIdentity.getIdentity()?.serverUrl,A),B={providerId:"opencode",sessionId:e,messageId:t,createdAt:(new Date).toISOString()},E&&(0,y.logSessionIdentity)(r,"_meta",{sessionId:e,messageId:t})}else if(M=r,D=x,P||(P=!0,A.warn("No _meta.sessionId on tool call: caller not on alchemylab-opencode fork.",{tool:M,metaKeys:D?Object.keys(D):null})),!1!==z?.requiresSession)throw(0,f.createMcpProtocolError)(`_meta.sessionId required for tool '${r}'`,{tool:r})
2962
+ a&&((0,m.isInWorkDir)(c,"setup-worktrees",a)||(0,m.isInWorkDir)(c,"test-worktrees",a))?(q.set(t,a),e.workspaceManager.setSessionWorktree(t,a)):q.set(t,null)}catch{}}(n,e,p.sessionIdentity.getIdentity()?.serverUrl,A),B={providerId:"opencode",sessionId:e,messageId:t,createdAt:(new Date).toISOString()},E&&(0,y.logSessionIdentity)(r,"_meta",{sessionId:e,messageId:t})}else if(M=r,D=x,j||(j=!0,A.warn("No _meta.sessionId on tool call: caller not on alchemylab-opencode fork.",{tool:M,metaKeys:D?Object.keys(D):null})),!1!==z?.requiresSession)throw(0,f.createMcpProtocolError)(`_meta.sessionId required for tool '${r}'`,{tool:r})
2961
2963
  p.sessionIdentity.setCurrentCallOrigin(B)
2962
2964
  const L=B?.sessionId||x?.sessionId
2963
2965
  if(n?.workspaceManager){N=Date.now()
@@ -2996,28 +2998,39 @@ const y=t(87280)
2996
2998
  t(52462)
2997
2999
  const w=t(82245),b=t(75632),v=t(58185),k=t(58622),I=t(79236),$=t(94466),x=(i(t(70857)),t(11569)),S=t(97896),_=t(98537),E="true"===process.env.ALCHEMY_DEBUG_LOGS,C=new Set,q=new Map,T=new Map},65948(e,exports,t){exports.mcpConnectionDefs=void 0
2998
3000
  const r=t(76183),n=t(57034)
2999
- exports.mcpConnectionDefs=[{name:"mcp_connections",description:'The project\'s MCP connections: external tool servers the fleet may reach (Runtime > MCP Servers in the product). list = what is registered and whether it is on; propose = register one, switched off, for the user to switch on and grant to agents. Use propose when your work is or needs an MCP server: a server you built in this repository is proposed as transport "repo" with its Dockerfile; a published npm server as "boxed" with a pinned version; a hosted one as "remote" with its url. Never point the user at a config file: the product has no config file for this, and the generated ones are not theirs to edit.',schema:r.McpConnectionsSchema,annotations:{title:"MCP connections",readOnlyHint:!1},createsRecords:!0,handler:(e,t)=>(0,n.handleMcpConnections)(e,t.context,t.apiClient,t.logger,t.metrics)}]},57034(e,exports,t){exports.G=void 0,exports.handleMcpConnections=async function(e,t,i,a,c){const l=c.startTimer("tool_execution_time")
3000
- try{if("list"===e.operation){const e=await i.proxyGet(`/api/projects/${t.projectId}/mcp-servers`),r=Array.isArray(e)?e:e?.data??[]
3001
- if(l({success:!0}),0===r.length)return o('This project has no MCP connections registered. Propose one with operation "propose".')
3001
+ exports.mcpConnectionDefs=[{name:"mcp_connections",description:'The project\'s MCP connections: external tool servers the fleet may reach (Runtime > MCP Servers in the product). list = what is registered and whether it is on; propose = register one, switched off, for the user to switch on and grant to agents; update = correct one by name, passing only what was wrong (if it was on it goes off until the user switches it on again); remove = take back one that is switched off. Use propose when your work is or needs an MCP server: a server you built in this repository is proposed as transport "repo" with its Dockerfile; a published npm server as "boxed" with a pinned version; a hosted one as "remote" with its url. Never point the user at a config file: the product has no config file for this, and the generated ones are not theirs to edit.',schema:r.McpConnectionsSchema,annotations:{title:"MCP connections",readOnlyHint:!1},createsRecords:!0,handler:(e,t)=>(0,n.handleMcpConnections)(e,t.context,t.apiClient,t.logger,t.metrics)}]},57034(e,exports,t){function r(e,t,r={}){if("repo"===t){const t={dockerfile:String(e.dockerfile??r.dockerfile??"").trim(),...e.context??r.context?{context:String(e.context??r.context).trim()}:{},...e.environment??r.environment?{environment:e.environment??r.environment}:{}},n=(0,o.validateRepoConfig)(t)
3002
+ return n?{problem:n}:{config:t}}if("boxed"===t){const t=String(e.package??r.package??"").trim()
3003
+ if(!t||!(0,o.isPinnedPackage)(t))return{problem:"A boxed connection needs an npm package with an exact version, for example @scope/server@1.2.3, and the bin it runs."}
3004
+ const n=String(e.bin??r.bin??"").trim()
3005
+ return n?{config:{package:t,bin:n,...e.environment??r.environment?{environment:e.environment??r.environment}:{}}}:{problem:"A boxed connection needs the bin to run, the name under node_modules/.bin."}}if("remote"===t){const t=String(e.url??r.url??"").trim()
3006
+ return/^https?:\/\//.test(t)?{config:{url:t,...e.environment??r.headers?{headers:e.environment??r.headers}:{}}}:{problem:"A remote connection needs an http(s) url."}}return{problem:'transport must be "repo" (a Dockerfile in this repository), "boxed" (a pinned npm package) or "remote" (a url). A command that runs unconfined on the user\'s machine can only be registered by the user.'}}exports.G=void 0,exports.handleMcpConnections=async function(e,t,a,c,l){const d=l.startTimer("tool_execution_time")
3007
+ try{if("list"===e.operation){const e=await a.proxyGet(`/api/projects/${t.projectId}/mcp-servers`),r=Array.isArray(e)?e:e?.data??[]
3008
+ if(d({success:!0}),0===r.length)return s('This project has no MCP connections registered. Propose one with operation "propose".')
3002
3009
  const n=r.map(e=>{const t=Array.isArray(e.toolManifest)?`${e.toolManifest.length} tools`:"not probed yet",r="repo"===e.transport?`built from ${e.config?.dockerfile}`:"boxed"===e.transport?`package ${e.config?.package}`:"remote"===e.transport?e.config?.url:"a command on the host"
3003
3010
  return`- ${e.name}: ${e.enabled?e.status:"switched off"} (${e.transport}, ${r}, ${t})`})
3004
- return o(["MCP connections registered for this project:",...n,"","Which agents may use each one is set on the workflow's Agents tab."].join("\n"))}if("propose"!==e.operation)return s('operation must be "list" or "propose"')
3005
- const r=String(e.name??"").trim(),a=(0,n.validateServerName)(r)
3006
- if(a)return l({success:!1,error:"bad_name"}),s(a)
3007
- const c=e.transport
3008
- let d
3009
- if("repo"===c){d={dockerfile:String(e.dockerfile??"").trim(),...e.context?{context:String(e.context).trim()}:{},...e.environment?{environment:e.environment}:{}}
3010
- const t=(0,n.validateRepoConfig)(d)
3011
- if(t)return l({success:!1,error:"bad_config"}),s(t)}else if("boxed"===c){const t=String(e.package??"").trim()
3012
- if(!t||!(0,n.isPinnedPackage)(t))return l({success:!1,error:"bad_config"}),s("A boxed connection needs an npm package with an exact version, for example @scope/server@1.2.3, and the bin it runs.")
3013
- if(!String(e.bin??"").trim())return l({success:!1,error:"bad_config"}),s("A boxed connection needs the bin to run, the name under node_modules/.bin.")
3014
- d={package:t,bin:String(e.bin).trim(),...e.environment?{environment:e.environment}:{}}}else{if("remote"!==c)return l({success:!1,error:"bad_transport"}),s('transport must be "repo" (a Dockerfile in this repository), "boxed" (a pinned npm package) or "remote" (a url). A command that runs unconfined on the user\'s machine can only be registered by the user.')
3015
- if(!/^https?:\/\//.test(String(e.url??"")))return l({success:!1,error:"bad_config"}),s("A remote connection needs an http(s) url.")
3016
- d={url:String(e.url).trim(),...e.environment?{headers:e.environment}:{}}}const u=await i.proxyPost(`/api/projects/${t.projectId}/mcp-servers`,{name:r,transport:c,config:d,secretKeys:Array.isArray(e.secretKeys)?e.secretKeys:[],addedBySessionId:t.currentSessionId}),h=u?.data??u
3017
- l({success:!0})
3018
- const p="repo"===c?" The product builds its image from the Dockerfile when it is switched on, and rebuilds it whenever the files it is built from change on main; the repository is mounted read-only at /work, /scratch is writable memory, and the image's ENTRYPOINT is what runs.":""
3019
- return o(`Proposed MCP connection **${h?.name??r}** (${c}).${p} ${exports.G}`)}catch(e){return l({success:!1,error:"exception"}),a.warn("mcp_connections failed",{error:(0,r.getErrorMessage)(e)}),s(`Could not do that: ${(0,r.getErrorMessage)(e)}`)}}
3020
- const r=t(58824),n=t(49779),o=e=>({content:[{type:"text",text:e}]}),s=e=>({content:[{type:"text",text:e}],isError:!0})
3011
+ return s(["MCP connections registered for this project:",...n,"","Which agents may use each one is set on the workflow's Agents tab."].join("\n"))}if("update"===e.operation||"remove"===e.operation)return await async function(e,t,n,o){const a=String(e.name??"").trim()
3012
+ if(!a)return o({success:!1,error:"bad_name"}),i('Name the connection to change (operation "list" shows them).')
3013
+ const c=await n.proxyGet(`/api/projects/${t.projectId}/mcp-servers`),l=Array.isArray(c)?c:c?.data??[],d=l.find(e=>e.name===a)
3014
+ if(!d)return o({success:!1,error:"not_found"}),i(`No MCP connection named ${a}. These are registered: ${l.map(e=>e.name).join(", ")||"none"}.`)
3015
+ if("remove"===e.operation)return d.enabled?(o({success:!1,error:"enabled"}),i(`${a} is switched on; only the user can remove it. Change it with update instead, or ask the user.`)):(await n.proxyDelete(`/api/projects/${t.projectId}/mcp-servers/${encodeURIComponent(d.id)}`),o({success:!0}),s(`Removed the MCP connection **${a}**.`))
3016
+ const u=e.transport??d.transport,h={}
3017
+ if(void 0!==e.transport||["dockerfile","context","package","bin","url","environment"].some(t=>void 0!==e[t])){const t=r(e,u,e.transport&&e.transport!==d.transport?{}:d.config??{})
3018
+ if("problem"in t)return o({success:!1,error:"bad_config"}),i(t.problem)
3019
+ h.config=t.config,e.transport&&e.transport!==d.transport&&(h.transport=e.transport)}if(Array.isArray(e.secretKeys)&&(h.secretKeys=e.secretKeys),0===Object.keys(h).length)return o({success:!1,error:"nothing"}),i("Nothing to change: pass the fields that are wrong (url, package, bin, dockerfile, context, environment, secretKeys or transport).")
3020
+ const p=await n.proxyPatch(`/api/projects/${t.projectId}/mcp-servers/${encodeURIComponent(d.id)}`,h),f=p?.data??p
3021
+ o({success:!0})
3022
+ const m=d.enabled&&f&&!1===f.enabled
3023
+ return s(`Changed the MCP connection **${a}** (${f?.transport??u}).`+(m?" It was switched on, so it is now switched OFF until the user switches it on again under Runtime > MCP Servers.":d.enabled?"":` ${exports.G}`))}(e,t,a,d)
3024
+ if("propose"!==e.operation)return i('operation must be "list", "propose", "update" or "remove"')
3025
+ const n=String(e.name??"").trim(),c=(0,o.validateServerName)(n)
3026
+ if(c)return d({success:!1,error:"bad_name"}),i(c)
3027
+ const l=e.transport,u=r(e,l)
3028
+ if("problem"in u)return d({success:!1,error:"bad_config"}),i(u.problem)
3029
+ const h=u.config,p=await a.proxyPost(`/api/projects/${t.projectId}/mcp-servers`,{name:n,transport:l,config:h,secretKeys:Array.isArray(e.secretKeys)?e.secretKeys:[],addedBySessionId:t.currentSessionId}),f=p?.data??p
3030
+ d({success:!0})
3031
+ const m="repo"===l?" The product builds its image from the Dockerfile when it is switched on, and rebuilds it whenever the files it is built from change on main; the repository is mounted read-only at /work, /scratch is writable memory, and the image's ENTRYPOINT is what runs.":""
3032
+ return s(`Proposed MCP connection **${f?.name??n}** (${l}).${m} ${exports.G}`)}catch(e){return d({success:!1,error:"exception"}),c.warn("mcp_connections failed",{error:(0,n.getErrorMessage)(e)}),i(`Could not do that: ${(0,n.getErrorMessage)(e)}`)}}
3033
+ const n=t(58824),o=t(49779),s=e=>({content:[{type:"text",text:e}]}),i=e=>({content:[{type:"text",text:e}],isError:!0})
3021
3034
  exports.G="It is registered switched OFF. The user switches it on under Runtime > MCP Servers and names the agents that may use it on the workflow's Agents tab; nothing reaches it until both are done. Say this in your handover instead of pointing at any config file."},23322(e,exports,t){var r,n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
3022
3035
  var o=Object.getOwnPropertyDescriptor(t,r)
3023
3036
  o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,o)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),o=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),s=this&&this.__importStar||(r=function(e){return r=Object.getOwnPropertyNames||function(e){var t=[]
@@ -3312,10 +3325,10 @@ return Array.isArray(t)&&0!==t.length?t.map(e=>{const t=[`- ${e.target??"a file"
3312
3325
  const r=Array.isArray(e.misses)?e.misses:[]
3313
3326
  for(const e of r)t.push(` - no match: \`${String(e)}\``)
3314
3327
  return t.join("\n")}).join("\n"):"The operation reported no per-file detail."}exports.handleQuickChange=async function(e,$,x,S,_,E,C,q){const T=_.child({tool:"quick_edit"}),R=Date.now()
3315
- try{const P=S.getRequestClient(),j=S.getTaskClient(),O=S.getFileClient(),M=S.getToolRecordClient(),{title:D,description:F,follows:N,...z}=e,B=e.comment||D
3328
+ try{const j=S.getRequestClient(),P=S.getTaskClient(),O=S.getFileClient(),M=S.getToolRecordClient(),{title:D,description:F,follows:N,...z}=e,B=e.comment||D
3316
3329
  T.info("Starting quick_edit workflow",{title:D,operationType:$})
3317
3330
  let L=!1
3318
- try{const e=await P.listRequests({limit:2,sortBy:"created_at",sortDirection:"desc"})
3331
+ try{const e=await j.listRequests({limit:2,sortBy:"created_at",sortDirection:"desc"})
3319
3332
  e&&2===e.length&&e.every(e=>"quick-edit"===e.type)&&(L=!0,T.info("Detected two consecutive quick-edits, will recommend normal request"))}catch(e){T.warn("Could not check recent requests for recommendation",{error:e})}const H=[]
3320
3333
  let U=[],W=null
3321
3334
  const{execFile:G}=await Promise.resolve().then(()=>t.t(35317,23)),V=x.mainBasePath||x.basePath,K=e=>new Promise(t=>G("git",e,{cwd:V,maxBuffer:33554432},(e,r)=>t(e?null:String(r)))),Y=await(0,b.resolveDefaultBranch)(V),J=function(e,t){return"write"===e?"string"!=typeof t?.path||t.documentId?[]:[t.path]:(Array.isArray(t?.operations)?t.operations:[]).filter(e=>"string"==typeof e?.path&&!e.documentId).map(e=>e.path)}($,z),Q=await(0,v.editFromOldPicture)({sessionId:x.currentSessionId,repoDir:V,defaultBranch:Y,relPaths:J})
@@ -3332,7 +3345,7 @@ U=(0,a.emptiedFiles)(t),W=(0,c.contentLoss)(t)}catch(e){T.warn("quick edit pre-c
3332
3345
  try{const t=await S.proxyGet(`/api/projects/${x.projectId}/test-processes`),r=Array.isArray(t)?t:Array.isArray(t?.data)?t.data:[],n=async e=>(await K(["ls-tree","-r","--name-only",`refs/heads/${Y}`,"--",e])??"").split("\n").filter(Boolean)
3333
3346
  e=await(0,a.checksLosingFiles)((0,a.emptiedAsDeletes)(U),r,n)}catch(e){return T.warn("quick edit refused: the project's checks could not be read",{error:(0,w.getErrorMessage)(e)}),{content:[{type:"text",text:"Not done: this edit empties files, and the project's checks could not be read to see whether any of them covers those files. File it with create_request instead. Nothing was changed or created."}],isError:!0}}if(e.length>0)return T.info("quick edit refused: it would take files away from a check",{losses:e}),{content:[{type:"text",text:(0,a.checkLossRefusal)(e)}],isError:!0}}if(W)return T.info("quick edit refused: it takes content out",{removed:W.removed,added:W.added,files:W.files.map(e=>e.path)}),{content:[{type:"text",text:(0,c.contentLossRefusal)(W)}],isError:!0}
3334
3347
  T.debug("Creating quick_edit request")
3335
- const Z=q?.sessionId??x.currentSessionId,X="string"==typeof Z&&/^ses_/.test(Z)?Z:void 0,ee=(await(0,k.messagesToChooseFrom)(x.mainBasePath,q)).length>0?null:await(0,k.exchangeKeyOfCall)(x.mainBasePath,q),te=await P.createRequest({title:D,description:F,type:"quick-edit",acceptanceCriteria:[],...X?{creatorSessionId:X}:{},...void 0!==ee?{exchangeKey:ee}:{},..."string"==typeof N&&/^req\d{6}$/.test(N)?{originRequestId:N}:{}})
3348
+ const Z=q?.sessionId??x.currentSessionId,X="string"==typeof Z&&/^ses_/.test(Z)?Z:void 0,ee=(await(0,k.messagesToChooseFrom)(x.mainBasePath,q)).length>0?null:await(0,k.exchangeKeyOfCall)(x.mainBasePath,q),te=await j.createRequest({title:D,description:F,type:"quick-edit",acceptanceCriteria:[],...X?{creatorSessionId:X}:{},...void 0!==ee?{exchangeKey:ee}:{},..."string"==typeof N&&/^req\d{6}$/.test(N)?{originRequestId:N}:{}})
3336
3349
  if(!te||!te.id)throw new Error("Failed to create request")
3337
3350
  const re=te.id
3338
3351
  let ne,oe
@@ -3340,67 +3353,67 @@ T.info("Created request",{requestId:re})
3340
3353
  let se=x
3341
3354
  try{if(!x.workspaceManager)throw new Error("Quick edits need the workspace manager to create their worktree")
3342
3355
  oe=await x.workspaceManager.bindSessionToRequestWorktree(o(re),re),se={...x,currentSessionId:o(re),basePath:oe,git:(0,y.simpleGit)(oe),...x.documentFileManager&&S?{documentFileManager:(0,I.requestScopedDocuments)(x.documentFileManager,o(re),{...(0,I.heldDocumentDepsFrom)(S,T),requestFor:async()=>re},T)}:{}},T.info("Quick edit worktree ready",{requestId:re,worktreePath:oe}),T.debug("Creating task")
3343
- const e=await j.createTask({requestId:re,projectId:x.projectId,title:`Execute ${$} operation`,description:`Quick change: ${D}`})
3356
+ const e=await P.createTask({requestId:re,projectId:x.projectId,title:`Execute ${$} operation`,description:`Quick change: ${D}`})
3344
3357
  if(!e||!e.id)throw new Error("Failed to create task")
3345
3358
  let b
3346
- if(ne=e.id,T.info("Created task",{taskId:ne}),T.debug("Executing file operation",{operationType:$}),"write"===$)b=await(0,u.handleWriteFile)({taskId:ne,...z,comment:B},se,O,j,M,P,_,E,C)
3359
+ if(ne=e.id,T.info("Created task",{taskId:ne}),T.debug("Executing file operation",{operationType:$}),"write"===$)b=await(0,u.handleWriteFile)({taskId:ne,...z,comment:B},se,O,P,M,j,_,E,C)
3347
3360
  else{if("replace"!==$)throw new l.ValidationError(`Unsupported operation type: ${$}`)
3348
- b=await(0,h.handleReplaceInFiles)({taskId:ne,...z,comment:B},se,j,M,P,_,E,C)}if(b.isError){T.error("File operation failed, cleaning up request and task",{requestId:re,taskId:ne})
3349
- try{await j.updateTaskStatus(ne,"canceled"),T.info("Canceled task after operation failure",{taskId:ne})}catch(e){T.warn("Failed to cancel task during cleanup",{taskId:ne,error:e instanceof Error?e.message:String(e)})}try{await P.updateRequest(re,{status:"canceled"}),T.info("Canceled request after operation failure",{requestId:re}),x.workspaceManager&&(await x.workspaceManager.cancelRequest(re),T.info("Cleaned up branch/worktree after operation failure",{requestId:re}))}catch(e){T.warn("Failed to cancel request during cleanup",{requestId:re,error:e instanceof Error?e.message:String(e)})}return{content:[{type:"text",text:`\u274c Quick change failed during ${$} operation:\n\n${b.content[0].text}\n\nThe request (${re}) and task have been canceled and cleaned up.`}],isError:!0}}if(H.length>0)try{const e=await Promise.resolve().then(()=>t.t(91943,23)),r=await Promise.resolve().then(()=>t.t(16928,23)),n=[]
3361
+ b=await(0,h.handleReplaceInFiles)({taskId:ne,...z,comment:B},se,P,M,j,_,E,C)}if(b.isError){T.error("File operation failed, cleaning up request and task",{requestId:re,taskId:ne})
3362
+ try{await P.updateTaskStatus(ne,"canceled"),T.info("Canceled task after operation failure",{taskId:ne})}catch(e){T.warn("Failed to cancel task during cleanup",{taskId:ne,error:e instanceof Error?e.message:String(e)})}try{await j.updateRequest(re,{status:"canceled"}),T.info("Canceled request after operation failure",{requestId:re}),x.workspaceManager&&(await x.workspaceManager.cancelRequest(re),T.info("Cleaned up branch/worktree after operation failure",{requestId:re}))}catch(e){T.warn("Failed to cancel request during cleanup",{requestId:re,error:e instanceof Error?e.message:String(e)})}return{content:[{type:"text",text:`\u274c Quick change failed during ${$} operation:\n\n${b.content[0].text}\n\nThe request (${re}) and task have been canceled and cleaned up.`}],isError:!0}}if(H.length>0)try{const e=await Promise.resolve().then(()=>t.t(91943,23)),r=await Promise.resolve().then(()=>t.t(16928,23)),n=[]
3350
3363
  for(const t of H){const o=await e.readFile(r.join(oe??se.basePath,t.path),"utf8").catch(()=>null)
3351
3364
  n.push({path:t.path,before:t.before,after:o})}const o=(0,a.emptiedFiles)(n)
3352
3365
  if(o.length>0){let e=null
3353
3366
  try{const t=await S.proxyGet(`/api/projects/${x.projectId}/test-processes`),r=Array.isArray(t)?t:Array.isArray(t?.data)?t.data:[]
3354
- e=await(0,a.checksLosingFiles)((0,a.emptiedAsDeletes)(o),r,async e=>[e])}catch{e=null}if(null===e||e.length>0)return await j.updateTaskStatus(ne,"canceled").catch(()=>{}),await P.updateRequest(re,{status:"canceled"}).catch(()=>{}),await(x.workspaceManager?.cancelRequest(re).catch(()=>{})),T.warn("quick edit emptied a checked file after an approximate match; discarded",{requestId:re,emptiedAfter:o}),{content:[{type:"text",text:`${e?(0,a.checkLossRefusal)(e).replace(/^Not done:/,"Not kept:").replace(/ Nothing was changed or created\.$/,""):"Not kept: this edit left files empty, and the project's checks could not be read to see whether any of them covers those files."}\n\nThe edit was discarded before it reached ${Y} and ${re} is canceled.`}],isError:!0}}}catch(e){T.warn("quick edit post-check could not run; keeping the edit",{requestId:re,error:e instanceof Error?e.message:String(e)})}const k=(0,d.readAlchemyMeta)(b),q=(A=k,!(!1===A?.failed))
3355
- if(q?T.warn("File operation completed with partial failures",{requestId:re}):T.info("File operation completed successfully"),q)return await j.updateTaskStatus(ne,"canceled").catch(()=>{}),await P.updateRequest(re,{status:"canceled"}).catch(()=>{}),await(x.workspaceManager?.cancelRequest(re).catch(()=>{})),x.workspaceManager?.releaseSession(o(re)),T.warn("quick edit partially failed; discarded whole",{requestId:re}),{content:[{type:"text",text:`\u274c Not kept: part of this edit failed, and a quick edit is merged whole or not at all, so ${Y} is unchanged. ${re} is canceled.\n\nRead the whole file again (its current text, not what you expected), then retry with replacements that all match. The parts that matched were discarded too: no file below changed on ${Y}.\n\n${i(k)}`}],isError:!0}
3367
+ e=await(0,a.checksLosingFiles)((0,a.emptiedAsDeletes)(o),r,async e=>[e])}catch{e=null}if(null===e||e.length>0)return await P.updateTaskStatus(ne,"canceled").catch(()=>{}),await j.updateRequest(re,{status:"canceled"}).catch(()=>{}),await(x.workspaceManager?.cancelRequest(re).catch(()=>{})),T.warn("quick edit emptied a checked file after an approximate match; discarded",{requestId:re,emptiedAfter:o}),{content:[{type:"text",text:`${e?(0,a.checkLossRefusal)(e).replace(/^Not done:/,"Not kept:").replace(/ Nothing was changed or created\.$/,""):"Not kept: this edit left files empty, and the project's checks could not be read to see whether any of them covers those files."}\n\nThe edit was discarded before it reached ${Y} and ${re} is canceled.`}],isError:!0}}}catch(e){T.warn("quick edit post-check could not run; keeping the edit",{requestId:re,error:e instanceof Error?e.message:String(e)})}const k=(0,d.readAlchemyMeta)(b),q=(A=k,!(!1===A?.failed))
3368
+ if(q?T.warn("File operation completed with partial failures",{requestId:re}):T.info("File operation completed successfully"),q)return await P.updateTaskStatus(ne,"canceled").catch(()=>{}),await j.updateRequest(re,{status:"canceled"}).catch(()=>{}),await(x.workspaceManager?.cancelRequest(re).catch(()=>{})),x.workspaceManager?.releaseSession(o(re)),T.warn("quick edit partially failed; discarded whole",{requestId:re}),{content:[{type:"text",text:`\u274c Not kept: part of this edit failed, and a quick edit is merged whole or not at all, so ${Y} is unchanged. ${re} is canceled.\n\nRead the whole file again (its current text, not what you expected), then retry with replacements that all match. The parts that matched were discarded too: no file below changed on ${Y}.\n\n${i(k)}`}],isError:!0}
3356
3369
  let F=""
3357
3370
  if(oe&&!s($,z)){let e=null,n=null
3358
3371
  const s=`The edit was discarded before it reached ${Y} and ${re} is canceled.`
3359
3372
  try{const r=await async function(e,r){const{execFile:n}=await Promise.resolve().then(()=>t.t(35317,23)),o=await Promise.resolve().then(()=>t.t(91943,23)),s=await Promise.resolve().then(()=>t.t(16928,23)),i=t=>new Promise((r,o)=>n("git",t,{cwd:e,maxBuffer:67108864},(e,t)=>e?o(e):r(String(t)))),a=e=>e.split("\0").filter(Boolean),c=a(await i(["diff","--no-renames","--name-only","-z",`refs/heads/${r}`])),l=a(await i(["ls-files","--others","--exclude-standard","-z"])),d=[]
3360
3373
  for(const t of[...new Set([...c,...l])]){const n=await i(["show",`refs/heads/${r}:${t}`]).catch(()=>null),a=await o.readFile(s.join(e,t),"utf8").catch(()=>null)
3361
3374
  d.push({path:t,before:n,after:a})}return d}(oe,Y)
3362
- n=(0,c.quickEditShapeRefusal)((0,c.quickEditShape)(r),{discarded:s}),e=(0,c.contentLoss)(r)}catch(e){T.warn("quick edit content check could not run; keeping the edit",{requestId:re,error:(0,w.getErrorMessage)(e)})}if(n)return await j.updateTaskStatus(ne,"canceled").catch(()=>{}),await P.updateRequest(re,{status:"canceled"}).catch(()=>{}),await(x.workspaceManager?.cancelRequest(re).catch(()=>{})),x.workspaceManager?.releaseSession(o(re)),T.warn("quick edit was not a small edit to an existing file; discarded",{requestId:re}),{content:[{type:"text",text:n}],isError:!0}
3375
+ n=(0,c.quickEditShapeRefusal)((0,c.quickEditShape)(r),{discarded:s}),e=(0,c.contentLoss)(r)}catch(e){T.warn("quick edit content check could not run; keeping the edit",{requestId:re,error:(0,w.getErrorMessage)(e)})}if(n)return await P.updateTaskStatus(ne,"canceled").catch(()=>{}),await j.updateRequest(re,{status:"canceled"}).catch(()=>{}),await(x.workspaceManager?.cancelRequest(re).catch(()=>{})),x.workspaceManager?.releaseSession(o(re)),T.warn("quick edit was not a small edit to an existing file; discarded",{requestId:re}),{content:[{type:"text",text:n}],isError:!0}
3363
3376
  if(F=await async function(e,n){const{execFile:o}=await Promise.resolve().then(()=>t.t(35317,23))
3364
- return r(await new Promise((t,r)=>o("git",["diff","--no-color","--no-renames","-U1",`refs/heads/${n}`],{cwd:e,maxBuffer:8388608},(e,n)=>e?r(e):t(String(n)))))}(oe,Y).catch(()=>""),e)return await j.updateTaskStatus(ne,"canceled").catch(()=>{}),await P.updateRequest(re,{status:"canceled"}).catch(()=>{}),await(x.workspaceManager?.cancelRequest(re).catch(()=>{})),x.workspaceManager?.releaseSession(o(re)),T.warn("quick edit took content out; discarded",{requestId:re,removed:e.removed,added:e.added,files:e.files.map(e=>e.path)}),{content:[{type:"text",text:(0,c.contentLossRefusal)(e,{discarded:`The edit was discarded before it reached ${Y} and ${re} is canceled.`})}],isError:!0}}T.debug("Completing task")
3377
+ return r(await new Promise((t,r)=>o("git",["diff","--no-color","--no-renames","-U1",`refs/heads/${n}`],{cwd:e,maxBuffer:8388608},(e,n)=>e?r(e):t(String(n)))))}(oe,Y).catch(()=>""),e)return await P.updateTaskStatus(ne,"canceled").catch(()=>{}),await j.updateRequest(re,{status:"canceled"}).catch(()=>{}),await(x.workspaceManager?.cancelRequest(re).catch(()=>{})),x.workspaceManager?.releaseSession(o(re)),T.warn("quick edit took content out; discarded",{requestId:re,removed:e.removed,added:e.added,files:e.files.map(e=>e.path)}),{content:[{type:"text",text:(0,c.contentLossRefusal)(e,{discarded:`The edit was discarded before it reached ${Y} and ${re} is canceled.`})}],isError:!0}}T.debug("Completing task")
3365
3378
  try{await(0,p.handleCompleteTask)({taskId:ne,summary:`${D}${q?" (partial success)":""}`},se,S,_,E),T.info("Task completed successfully",{taskId:ne})}catch(e){T.error("Task completion via handleCompleteTask failed, attempting direct status update",{taskId:ne,error:e instanceof Error?e.message:String(e),errorStack:e instanceof Error?e.stack:void 0})
3366
- try{await j.updateTaskStatus(ne,"completed"),T.info("Task completed via direct updateTaskStatus call",{taskId:ne})}catch(e){return T.error("Direct task completion ALSO failed - task may be stuck in in_progress",{taskId:ne,error:e instanceof Error?e.message:String(e),errorStack:e instanceof Error?e.stack:void 0,operationType:$,isDocumentOperation:!!z.documentId}),{content:[{type:"text",text:`\u26a0\ufe0f Quick change operation succeeded but task completion failed.\n\n**Request:** ${re}\n**Task:** ${ne}\n**Issue:** Could not mark task as completed - it remains in 'in_progress' state\n\nThe ${$} operation was successful, but we couldn't automatically complete the task. Please use the complete-task tool manually with taskId: ${ne}\n\nError: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}}const N=(()=>{try{return S.getProjectId?.()??null}catch{return null}})(),U=N?await(0,I.requestDocumentEdits)({get:e=>S.proxyGet(e)},N,re).then(e=>r(e.map(e=>e.diff).join(""))).catch(()=>""):""
3379
+ try{await P.updateTaskStatus(ne,"completed"),T.info("Task completed via direct updateTaskStatus call",{taskId:ne})}catch(e){return T.error("Direct task completion ALSO failed - task may be stuck in in_progress",{taskId:ne,error:e instanceof Error?e.message:String(e),errorStack:e instanceof Error?e.stack:void 0,operationType:$,isDocumentOperation:!!z.documentId}),{content:[{type:"text",text:`\u26a0\ufe0f Quick change operation succeeded but task completion failed.\n\n**Request:** ${re}\n**Task:** ${ne}\n**Issue:** Could not mark task as completed - it remains in 'in_progress' state\n\nThe ${$} operation was successful, but we couldn't automatically complete the task. Please use the complete-task tool manually with taskId: ${ne}\n\nError: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}}const N=(()=>{try{return S.getProjectId?.()??null}catch{return null}})(),U=N?await(0,I.requestDocumentEdits)({get:e=>S.proxyGet(e)},N,re).then(e=>r(e.map(e=>e.diff).join(""))).catch(()=>""):""
3367
3380
  U&&(F=F?`${F}\n${U}`:U),T.debug("Completing request")
3368
3381
  const W=q?`Quick change completed with partial success: ${D}. Some replacements failed - see details below.`:`${D}${F?`\n\n\`\`\`diff\n${F}\n\`\`\``:""}`,G=q?`${$} operation partially completed - some operations succeeded, some failed`:`${$} operation executed successfully`
3369
3382
  let Q=!1
3370
3383
  const Z=await K(["rev-list","--count",`refs/heads/${Y}..refs/heads/requests/${re}`])
3371
3384
  let X
3372
3385
  if(null!==Z&&Number(Z.trim())>0?Q=!0:await(x.workspaceManager?.cancelRequest(re).catch(e=>{T.warn("Could not discard the empty quick-edit worktree",{requestId:re,error:(0,w.getErrorMessage)(e)})})),x.workspaceManager?.releaseSession(o(re)),Q){try{const e=await(0,f.handleCompleteRequest)({requestId:re,summary:W},x,S,_,E,C)
3373
- e.isError&&T.warn("complete_request reported an error; attempting merge anyway (merge revalidates)",{requestId:re,error:e.content[0]?.text})}catch(e){T.warn("complete_request threw; attempting merge anyway (merge revalidates)",{requestId:re,error:(0,w.getErrorMessage)(e)})}const e=await P.getRequest(re).catch(()=>null)
3386
+ e.isError&&T.warn("complete_request reported an error; attempting merge anyway (merge revalidates)",{requestId:re,error:e.content[0]?.text})}catch(e){T.warn("complete_request threw; attempting merge anyway (merge revalidates)",{requestId:re,error:(0,w.getErrorMessage)(e)})}const e=await j.getRequest(re).catch(()=>null)
3374
3387
  if("ready_for_review"===e?.status)return T.info("Quick edit waits for the user's sign-off",{requestId:re}),{content:[{type:"text",text:n(re,D,Y)}],...(0,d.alchemyMeta)({kind:`quick-${$}`,toolRecordId:(0,d.readAlchemyMeta)(b)?.toolRecordId})}
3375
3388
  let t=[]
3376
- try{const e=await P.getRequest(re),r=e?.acceptanceCriteria||[]
3389
+ try{const e=await j.getRequest(re),r=e?.acceptanceCriteria||[]
3377
3390
  t=Array.from((0,g.buildCriteriaKeyMap)(r).keys()).map(e=>({key:e,evidence:G}))}catch(e){T.debug("Could not build criteria verifications",{requestId:re,error:(0,w.getErrorMessage)(e)})}const r=new Map
3378
3391
  for(const e of J)r.set(e.replace(/^\.\//,""),(await K(["rev-parse","--verify","--quiet",`refs/heads/requests/${re}:${e.replace(/^\.\//,"")}`]))?.trim())
3379
3392
  const s=await(0,m.handleMergeRequest)({requestId:re,verifications:t},x,S,_,E,C)
3380
3393
  let i=null
3381
- try{i=await P.getRequest(re)}catch{}if(!s.isError&&"completed"===i?.status)for(const[e,t]of r){const r=(await K(["rev-parse","--verify","--quiet",`refs/heads/${Y}:${e}`]))?.trim()
3394
+ try{i=await j.getRequest(re)}catch{}if(!s.isError&&"completed"===i?.status)for(const[e,t]of r){const r=(await K(["rev-parse","--verify","--quiet",`refs/heads/${Y}:${e}`]))?.trim()
3382
3395
  t&&r===t&&await(0,v.noteMainFileRead)(x.currentSessionId,V,Y,e)}if(s.isError||"completed"!==i?.status){const e=s.content?.[0]?.text||"unknown merge failure"
3383
3396
  T.error("Quick change merge to main failed",{requestId:re,status:i?.status,mergeText:e})
3384
3397
  const t=(await K(["rev-parse","--verify","--quiet",`refs/heads/requests/${re}`]))?.trim(),r=!t||null!==await K(["merge-base","--is-ancestor",t,`refs/heads/${Y}`])
3385
- return r?{content:[{type:"text",text:`\u26a0\ufe0f Quick change applied but its completion did not finish cleanly.\n\n**Request:** ${re}\n**Title:** ${D}\n\n${r?`The ${$} operation succeeded and the change IS merged to main in git, but the request record could not be finalized (status: ${i?.status??"unknown"}).`:`The ${$} operation succeeded and is committed on branch \`requests/${re}\`, but it is NOT on ${Y}: the merge did not complete.`} The merge step reported:\n\n${e}\n\n${r?"The code is on main; only the request record needs attention.":`Resolve the issue, then merge with request_operations {"operation": "merge", "requestId": "${re}"}.`}`}],isError:!0}:(await P.updateRequest(re,{status:"canceled"}).catch(()=>{}),await(x.workspaceManager?.cancelRequest(re).catch(()=>{})),x.workspaceManager?.releaseSession(o(re)),T.warn("quick edit did not land; discarded whole",{requestId:re}),{content:[{type:"text",text:`\u274c Not kept: the edit could not be merged into ${Y}, and a quick edit is merged whole or not at all, so ${re} is canceled and ${Y} is unchanged. The merge step said:\n\n${e}\n\nIf the change is still wanted, file it with create_request: a worker then owns it through its checks.`}],isError:!0})}X=i?.mergeCommitSha,T.info("Request merged to main and completed",{requestId:re,mergeCommitSha:X})
3398
+ return r?{content:[{type:"text",text:`\u26a0\ufe0f Quick change applied but its completion did not finish cleanly.\n\n**Request:** ${re}\n**Title:** ${D}\n\n${r?`The ${$} operation succeeded and the change IS merged to main in git, but the request record could not be finalized (status: ${i?.status??"unknown"}).`:`The ${$} operation succeeded and is committed on branch \`requests/${re}\`, but it is NOT on ${Y}: the merge did not complete.`} The merge step reported:\n\n${e}\n\n${r?"The code is on main; only the request record needs attention.":`Resolve the issue, then merge with request_operations {"operation": "merge", "requestId": "${re}"}.`}`}],isError:!0}:(await j.updateRequest(re,{status:"canceled"}).catch(()=>{}),await(x.workspaceManager?.cancelRequest(re).catch(()=>{})),x.workspaceManager?.releaseSession(o(re)),T.warn("quick edit did not land; discarded whole",{requestId:re}),{content:[{type:"text",text:`\u274c Not kept: the edit could not be merged into ${Y}, and a quick edit is merged whole or not at all, so ${re} is canceled and ${Y} is unchanged. The merge step said:\n\n${e}\n\nIf the change is still wanted, file it with create_request: a worker then owns it through its checks.`}],isError:!0})}X=i?.mergeCommitSha,T.info("Request merged to main and completed",{requestId:re,mergeCommitSha:X})
3386
3399
  const a=`refs/heads/requests/${re}`,c=(await K(["rev-parse","--verify","--quiet",a]))?.trim()
3387
3400
  c&&null!==await K(["merge-base","--is-ancestor",c,`refs/heads/${Y}`])&&await K(["update-ref","-d",a,c])}else{if(("write"===$||"replace"===$||"manage"===$)&&!s($,z))return T.error("Quick-edit file change produced no commit; refusing to complete",{requestId:re}),{content:[{type:"text",text:`\u26a0\ufe0f Quick change ${re} produced no commit, so nothing reached ${Y}. The request is left open on purpose: completing it would claim a delivery git does not have. Retry the edit, or file it with create_request.`}],isError:!0}
3388
3401
  let e=!1
3389
- try{const t=await(0,f.handleCompleteRequest)({requestId:re,summary:W},x,S,_,E,C),r=t.isError?null:await P.getRequest(re).catch(()=>null)
3402
+ try{const t=await(0,f.handleCompleteRequest)({requestId:re,summary:W},x,S,_,E,C),r=t.isError?null:await j.getRequest(re).catch(()=>null)
3390
3403
  if(t.isError)T.error("Request completion failed, attempting direct completion",{requestId:re,error:t.content[0].text})
3391
3404
  else{if("ready_for_review"===r?.status)return{content:[{type:"text",text:n(re,D,Y)}]}
3392
- try{await P.updateRequest(re,{status:"completed",completionSummary:W}),T.info("Request finalized to completed",{requestId:re})}catch(e){T.warn("Failed to finalize request to completed, may be stuck at completing",{requestId:re,error:(0,w.getErrorMessage)(e)})}e=!0,T.info("Request completed successfully",{requestId:re})}}catch(e){T.error("Request completion threw exception, attempting direct completion",{requestId:re,error:e instanceof Error?e.message:String(e)})}if(!e)try{T.info("Attempting direct request completion via API",{requestId:re}),await P.updateRequest(re,{status:"completed",completionSummary:W}),e=!0,T.info("Request completed successfully via direct API call",{requestId:re})}catch(e){return T.error("Direct request completion also failed",{requestId:re,error:e instanceof Error?e.message:String(e)}),{content:[{type:"text",text:`\u26a0\ufe0f Quick change operation succeeded but request completion failed.\n\n**Request:** ${re}\n**Status:** Still in 'in_progress' - please complete manually\n\nThe file operation was successful, but we couldn't automatically complete the request. Please use the complete-request tool manually.`}],isError:!0}}}const ee=Date.now()-R
3405
+ try{await j.updateRequest(re,{status:"completed",completionSummary:W}),T.info("Request finalized to completed",{requestId:re})}catch(e){T.warn("Failed to finalize request to completed, may be stuck at completing",{requestId:re,error:(0,w.getErrorMessage)(e)})}e=!0,T.info("Request completed successfully",{requestId:re})}}catch(e){T.error("Request completion threw exception, attempting direct completion",{requestId:re,error:e instanceof Error?e.message:String(e)})}if(!e)try{T.info("Attempting direct request completion via API",{requestId:re}),await j.updateRequest(re,{status:"completed",completionSummary:W}),e=!0,T.info("Request completed successfully via direct API call",{requestId:re})}catch(e){return T.error("Direct request completion also failed",{requestId:re,error:e instanceof Error?e.message:String(e)}),{content:[{type:"text",text:`\u26a0\ufe0f Quick change operation succeeded but request completion failed.\n\n**Request:** ${re}\n**Status:** Still in 'in_progress' - please complete manually\n\nThe file operation was successful, but we couldn't automatically complete the request. Please use the complete-request tool manually.`}],isError:!0}}}const ee=Date.now()-R
3393
3406
  T.info("Quick fix completed",{requestId:re,duration:ee,hasPartialFailure:q})
3394
3407
  const te=(0,d.readAlchemyMeta)(b)?.toolRecordId,ie=Q?`completed: it is in the project now${X?` (commit ${X.substring(0,8)})`:""}.\n**Active branch:** main`:"recorded (a document edit; no file in the project changed)."
3395
3408
  let ae
3396
- return ae=q?`\u26a0\ufe0f Quick change completed with partial success\n\n**Request:** ${re}\n**Title:** ${D}\n**Operation:** ${$}\n**Duration:** ${ee}ms\n**Status:** Some operations succeeded, some failed\n\nThe successful changes have been applied and ${ie}\n\n**\u26a0\ufe0f Note:** This quick-fix had partial failures. See operation details below:\n\n${b.content[0].text}`:`\u2705 Quick change completed successfully!\n\n**Request:** ${re}\n**Title:** ${D}\n**Operation:** ${$}\n**Duration:** ${ee}ms\n\nThe change has been applied and ${ie}`+(te?`\n[RECORD:${te}]`:""),L&&(ae+="\n\n\u{1f4a1} **Recommendation:** You've created several quick-edits in a row. For better traceability and organization, consider creating a proper code request with multiple tasks for your next change."),{content:[{type:"text",text:ae}],...(0,d.alchemyMeta)({kind:`quick-${$}`,toolRecordId:te})}}catch(e){if(T.error("Quick change workflow failed after request creation, cleaning up",{requestId:re,error:(0,w.getErrorMessage)(e)}),ne)try{await j.updateTaskStatus(ne,"canceled"),T.info("Canceled task after workflow failure",{taskId:ne})}catch(e){T.warn("Failed to cancel task during cleanup",{taskId:ne,error:e instanceof Error?e.message:String(e)})}x.workspaceManager?.releaseSession(o(re))
3397
- try{await P.updateRequest(re,{status:"canceled"}),T.info("Canceled request after workflow failure",{requestId:re}),x.workspaceManager&&(await x.workspaceManager.cancelRequest(re),T.info("Cleaned up branch/worktree after workflow failure",{requestId:re}))}catch(e){T.warn("Failed to cancel request during cleanup",{requestId:re,error:e instanceof Error?e.message:String(e)})}throw e}}catch(e){const t=Date.now()-R
3409
+ return ae=q?`\u26a0\ufe0f Quick change completed with partial success\n\n**Request:** ${re}\n**Title:** ${D}\n**Operation:** ${$}\n**Duration:** ${ee}ms\n**Status:** Some operations succeeded, some failed\n\nThe successful changes have been applied and ${ie}\n\n**\u26a0\ufe0f Note:** This quick-fix had partial failures. See operation details below:\n\n${b.content[0].text}`:`\u2705 Quick change completed successfully!\n\n**Request:** ${re}\n**Title:** ${D}\n**Operation:** ${$}\n**Duration:** ${ee}ms\n\nThe change has been applied and ${ie}`+(te?`\n[RECORD:${te}]`:""),L&&(ae+="\n\n\u{1f4a1} **Recommendation:** You've created several quick-edits in a row. For better traceability and organization, consider creating a proper code request with multiple tasks for your next change."),{content:[{type:"text",text:ae}],...(0,d.alchemyMeta)({kind:`quick-${$}`,toolRecordId:te})}}catch(e){if(T.error("Quick change workflow failed after request creation, cleaning up",{requestId:re,error:(0,w.getErrorMessage)(e)}),ne)try{await P.updateTaskStatus(ne,"canceled"),T.info("Canceled task after workflow failure",{taskId:ne})}catch(e){T.warn("Failed to cancel task during cleanup",{taskId:ne,error:e instanceof Error?e.message:String(e)})}x.workspaceManager?.releaseSession(o(re))
3410
+ try{await j.updateRequest(re,{status:"canceled"}),T.info("Canceled request after workflow failure",{requestId:re}),x.workspaceManager&&(await x.workspaceManager.cancelRequest(re),T.info("Cleaned up branch/worktree after workflow failure",{requestId:re}))}catch(e){T.warn("Failed to cancel request during cleanup",{requestId:re,error:e instanceof Error?e.message:String(e)})}throw e}}catch(e){const t=Date.now()-R
3398
3411
  return T.error("Quick change failed",{error:(0,w.getErrorMessage)(e),duration:t}),e instanceof l.ValidationError?{content:[{type:"text",text:`\u274c ${e.message}`}],isError:!0}:{content:[{type:"text",text:`\u274c Quick change failed: ${(0,w.getErrorMessage)(e)}`}],isError:!0}}var A}
3399
3412
  const a=t(95122),c=t(81563),l=t(59860),d=t(82272),u=t(14079),h=t(69442),p=t(80355),f=t(15715),m=t(34306),g=t(65454),y=t(83807),w=t(58824),b=t(52232),v=t(91233),k=t(62032),I=t(95040)},57250(e,exports,t){exports.def=void 0
3400
3413
  const r=t(76183),n=t(43707)
3401
3414
  exports.def={name:"quick_replace",description:"Replace text in files or documents as a quick edit: operations [{ path | documentId, replacements [{ old_str, new_str, match_mode? }] }], fuzzy matching on by default. Requires title, description, comment, operations. The quick-edit rules are quick_write's.",schema:r.QuickReplaceSchema,annotations:{title:"Quick Replace",readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1},handler:(e,t)=>(0,n.handleQuickChange)(e,"replace",t.context,t.apiClient,t.logger,t.metrics,t.mcpServer,t.cliOrigin)}},40213(e,exports,t){exports.def=void 0
3402
3415
  const r=t(76183),n=t(43707)
3403
- exports.def={name:"quick_write",description:"Update a file that exists (path) or a document (documentId) as a quick edit; append:true adds to the end. content is a string or an array of lines (prefer the array for JSON, TOML, YAML). Requires title, description, content.\n\nA quick edit is a small change (at most 20 lines) to text or settings in an existing file (docs, copy, config values), never code (that goes to the worker on it via hand-over, or to a request). A new file, a larger edit or a net removal is refused: file a request. It is made on a file as you last read it with read_files: one you have not read, or that other work changed since, is refused until you read it again. Only for a change the user wants kept, never copies, scratch or preview files. It becomes a quick-edit request that merges on its own, unless Manual Autonomy or one of the user's recent checks on that file holds it for their sign-off.",schema:r.QuickWriteSchema,annotations:{title:"Quick Write",readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1},handler:(e,t)=>(0,n.handleQuickChange)(e,"write",t.context,t.apiClient,t.logger,t.metrics,t.mcpServer,t.cliOrigin)}},52462(e,exports,t){const r=t(82245),n=t(19080),o=t(5692),s=t(9030),i=t(12903),a=t(54607),c=t(49499),l=t(16770),d=t(8045),u=t(89697),h=t(39196),p=t(5459),f=t(94805),m=t(260),g=t(32283),y=t(74165),w=t(96111),b=t(80700),v=t(45837),k=t(56700),I=t(91535),$=t(57257),x=t(9230),S=t(34150),_=t(26473),E=t(6309),C=t(86317),q=t(61391),T=t(57713),R=t(96252),A=t(40213),P=t(57250),j=t(41197),O=t(15510),M=t(94669),D=t(56946),F=t(90346),N=t(28196),z=t(66808),B=t(1540),L=t(44973),H=t(48155),U=t(17613),W=t(4961),G=t(68456),V=t(75850),K=t(23322),Y=t(50003),J=t(55247),Q=t(57507),Z=t(8411),X=t(5169),ee=t(65948),te=t(98095),re=t(78002),ne=t(88849),oe=t(70542);(0,r.registerTool)(n.def),(0,r.registerTool)(o.def),(0,r.registerTool)(s.def),(0,r.registerTool)(i.def),(0,r.registerTool)(a.def),(0,r.registerTool)(c.def),(0,r.registerTool)(l.def),(0,r.registerTool)(d.def),(0,r.registerTool)(u.def),(0,r.registerTool)(h.def),(0,r.registerTool)(p.def),(0,r.registerTool)(f.def),(0,r.registerTool)(m.def),(0,r.registerTool)(g.def),(0,r.registerTool)(y.def),(0,r.registerTool)(w.def),(0,r.registerTool)(b.def),(0,r.registerTool)(v.def),(0,r.registerTool)(k.def),(0,r.registerTool)(I.def),(0,r.registerTool)(S.def),(0,r.registerTool)($.def),(0,r.registerTool)(x.def),(0,r.registerTool)(_.def),(0,r.registerTool)(E.def),(0,r.registerTool)(C.def),(0,r.registerTool)(q.def),(0,r.registerTool)(T.def),(0,r.registerTool)(R.def),(0,r.registerTool)(A.def),(0,r.registerTool)(P.def),(0,r.registerTool)(j.def),(0,r.registerTool)(O.def),(0,r.registerTool)(M.def),(0,r.registerTool)(D.def),(0,r.registerTool)(F.def),(0,r.registerTool)(N.def),(0,r.registerTool)(N.previewDef),(0,r.registerTool)(z.def),(0,r.registerTool)(z.cancelDef),(0,r.registerTool)(z.listDef),(0,r.registerTool)(z.followupDef),(0,r.registerTool)(B.def),(0,r.registerTool)(L.def),(0,r.registerTool)(H.def),(0,r.registerTool)(U.def),(0,r.registerTool)(W.def),(0,r.registerTool)(G.def),(0,r.registerTool)(V.def),(0,r.registerTools)(K.metaDefs),(0,r.registerTools)(Y.contractDefs),(0,r.registerTools)(J.testingDefs),(0,r.registerTools)(Q.environmentDefs),(0,r.registerTools)(Z.setupDefs),(0,r.registerTools)(X.resultDefs),(0,r.registerTools)(ee.mcpConnectionDefs),(0,r.registerTools)(te.experimentDefs),(0,r.registerTools)(re.visualDefs),(0,r.registerTools)(ne.checkingDefs),(0,r.registerTools)(oe.debugDefs),(0,t(82245).freezeRegistry)()},82245(e,exports,t){function r(e){if(h)throw new Error(`Tool registry is frozen: cannot register '${e.name}'. Core tools must be added in registrations.ts at build time.`)
3416
+ exports.def={name:"quick_write",description:"Update a file that exists (path) or a document (documentId) as a quick edit; append:true adds to the end. content is a string or an array of lines (prefer the array for JSON, TOML, YAML). Requires title, description, content.\n\nA quick edit is a small change (at most 20 lines) to text or settings in an existing file (docs, copy, config values), never code (that goes to the worker on it via hand-over, or to a request). A new file, a larger edit or a net removal is refused: file a request. It is made on a file as you last read it with read_files: one you have not read, or that other work changed since, is refused until you read it again. Only for a change the user wants kept, never copies, scratch or preview files. It becomes a quick-edit request that merges on its own, unless Manual Autonomy or one of the user's recent checks on that file holds it for their sign-off.",schema:r.QuickWriteSchema,annotations:{title:"Quick Write",readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1},handler:(e,t)=>(0,n.handleQuickChange)(e,"write",t.context,t.apiClient,t.logger,t.metrics,t.mcpServer,t.cliOrigin)}},52462(e,exports,t){const r=t(82245),n=t(19080),o=t(5692),s=t(9030),i=t(12903),a=t(54607),c=t(49499),l=t(16770),d=t(8045),u=t(89697),h=t(39196),p=t(5459),f=t(94805),m=t(260),g=t(32283),y=t(74165),w=t(96111),b=t(80700),v=t(45837),k=t(56700),I=t(91535),$=t(57257),x=t(9230),S=t(34150),_=t(26473),E=t(6309),C=t(86317),q=t(61391),T=t(57713),R=t(96252),A=t(40213),j=t(57250),P=t(41197),O=t(15510),M=t(94669),D=t(56946),F=t(90346),N=t(28196),z=t(66808),B=t(1540),L=t(44973),H=t(48155),U=t(17613),W=t(4961),G=t(68456),V=t(75850),K=t(23322),Y=t(50003),J=t(55247),Q=t(57507),Z=t(8411),X=t(5169),ee=t(65948),te=t(98095),re=t(78002),ne=t(88849),oe=t(70542);(0,r.registerTool)(n.def),(0,r.registerTool)(o.def),(0,r.registerTool)(s.def),(0,r.registerTool)(i.def),(0,r.registerTool)(a.def),(0,r.registerTool)(c.def),(0,r.registerTool)(l.def),(0,r.registerTool)(d.def),(0,r.registerTool)(u.def),(0,r.registerTool)(h.def),(0,r.registerTool)(p.def),(0,r.registerTool)(f.def),(0,r.registerTool)(m.def),(0,r.registerTool)(g.def),(0,r.registerTool)(y.def),(0,r.registerTool)(w.def),(0,r.registerTool)(b.def),(0,r.registerTool)(v.def),(0,r.registerTool)(k.def),(0,r.registerTool)(I.def),(0,r.registerTool)(S.def),(0,r.registerTool)($.def),(0,r.registerTool)(x.def),(0,r.registerTool)(_.def),(0,r.registerTool)(E.def),(0,r.registerTool)(C.def),(0,r.registerTool)(q.def),(0,r.registerTool)(T.def),(0,r.registerTool)(R.def),(0,r.registerTool)(A.def),(0,r.registerTool)(j.def),(0,r.registerTool)(P.def),(0,r.registerTool)(O.def),(0,r.registerTool)(M.def),(0,r.registerTool)(D.def),(0,r.registerTool)(F.def),(0,r.registerTool)(N.def),(0,r.registerTool)(N.previewDef),(0,r.registerTool)(z.def),(0,r.registerTool)(z.cancelDef),(0,r.registerTool)(z.listDef),(0,r.registerTool)(z.followupDef),(0,r.registerTool)(B.def),(0,r.registerTool)(L.def),(0,r.registerTool)(H.def),(0,r.registerTool)(U.def),(0,r.registerTool)(W.def),(0,r.registerTool)(G.def),(0,r.registerTool)(V.def),(0,r.registerTools)(K.metaDefs),(0,r.registerTools)(Y.contractDefs),(0,r.registerTools)(J.testingDefs),(0,r.registerTools)(Q.environmentDefs),(0,r.registerTools)(Z.setupDefs),(0,r.registerTools)(X.resultDefs),(0,r.registerTools)(ee.mcpConnectionDefs),(0,r.registerTools)(te.experimentDefs),(0,r.registerTools)(re.visualDefs),(0,r.registerTools)(ne.checkingDefs),(0,r.registerTools)(oe.debugDefs),(0,t(82245).freezeRegistry)()},82245(e,exports,t){function r(e){if(h)throw new Error(`Tool registry is frozen: cannot register '${e.name}'. Core tools must be added in registrations.ts at build time.`)
3404
3417
  if(u.has(e.name))throw new Error(`Duplicate tool registration: '${e.name}'`)
3405
3418
  d.push(e),u.set(e.name,e)}function n(e){const t=e.replace(/\s+/g," ").trim(),r=/^(.{20,200}?[.!?])(\s|$)/.exec(t)
3406
3419
  return r?r[1]:t.slice(0,200)}function o(e){if(Array.isArray(e))return e.map(o)
@@ -3431,38 +3444,38 @@ await new Promise(e=>setTimeout(e,s.pollMs??2e3))}if(!d||!r.has(String(d.status)
3431
3444
  if("completed"!==d.status)return{text:`The target of the thread of ${o} was not read: ${String(d.errorMessage||d.status)}.`,isError:!0}
3432
3445
  const u=await e.proxyGet(`/api/projects/${n}/threads/${encodeURIComponent(o)}`),h=(u?.data??u)?.target
3433
3446
  return h?.state?{text:t(o,h.state)}:{text:`The thread of ${o} has no target.`}}
3434
- const r=new Set(["completed","failed","canceled","cancelled","timeout","expired"])},15715(e,exports,t){function r(e,t){return`Not completed yet: ${e} was completed before, and the summary you pass now REPLACES the one the user reads when it lands. The earlier one:\n "${t.length>600?`${t.slice(0,597)}...`:t}"\nWrite a summary that describes everything ${e} delivers, with this round's fixes folded in (not only the fixes), and call complete again with replacesSummary: true.`}exports.handleCompleteRequest=async function(e,E,C,q,T,R,A){const P=q.child({tool:"complete_request"}),j=T.startTimer("tool_execution_time")
3447
+ const r=new Set(["completed","failed","canceled","cancelled","timeout","expired"])},15715(e,exports,t){function r(e,t){return`Not completed yet: ${e} was completed before, and the summary you pass now REPLACES the one the user reads when it lands. The earlier one:\n "${t.length>600?`${t.slice(0,597)}...`:t}"\nWrite a summary that describes everything ${e} delivers, with this round's fixes folded in (not only the fixes), and call complete again with replacesSummary: true.`}exports.handleCompleteRequest=async function(e,E,C,q,T,R,A){const j=q.child({tool:"complete_request"}),P=T.startTimer("tool_execution_time")
3435
3448
  try{const{requestId:s,summary:i,change:O,worthKnowing:M,skipTestsReason:D,skipTests:F,criteriaComments:N,couldNotCheck:z,guidance:B,replacesSummary:L,notChecked:H,show:U}=e
3436
3449
  if(!s)throw(0,o.createValidationError)("Request ID is required")
3437
3450
  if(!i&&!O)throw(0,o.createValidationError)("Summary is required")
3438
3451
  let W=null
3439
- try{W=await C.getRequestClient().getRequest(s)}catch(e){P.debug("the request could not be read before completing; completion continues",{requestId:s,error:(0,h.getErrorMessage)(e)})}const G="string"==typeof W?.roundOf&&!!W.roundOf
3452
+ try{W=await C.getRequestClient().getRequest(s)}catch(e){j.debug("the request could not be read before completing; completion continues",{requestId:s,error:(0,h.getErrorMessage)(e)})}const G="string"==typeof W?.roundOf&&!!W.roundOf
3440
3453
  if(!i&&!W)return{content:[{type:"text",text:`Not completed: ${s} could not be read just now, so nothing was recorded. Call complete again with the same arguments.`}],isError:!0}
3441
3454
  if(!i&&!G)throw(0,o.createValidationError)(`Summary is required: ${s} is not a round, and \`change\` is one change on a round.`)
3442
3455
  let V=i||O||""
3443
3456
  if(D&&F&&F.length>0)throw(0,o.createValidationError)("Provide either skipTestsReason (skip all) or skipTests (per-command), not both.")
3444
3457
  if(!0!==L){const e=String(W?.completionSummary??"").trim()
3445
- if(e)return P.info("re-completion refused until the summary is confirmed to cover the whole request",{requestId:s}),{content:[{type:"text",text:r(s,e)}],isError:!0}}P.info("Starting request completion",{requestId:s,skipAllRequested:!!D,perCommandSkipCount:F?.length||0})
3458
+ if(e)return j.info("re-completion refused until the summary is confirmed to cover the whole request",{requestId:s}),{content:[{type:"text",text:r(s,e)}],isError:!0}}j.info("Starting request completion",{requestId:s,skipAllRequested:!!D,perCommandSkipCount:F?.length||0})
3446
3459
  const K=A?.sessionId??E.currentSessionId,Y=A??(K?{providerId:"opencode",sessionId:K,createdAt:(new Date).toISOString()}:void 0)
3447
3460
  try{const e=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/commit-worktree-leftovers`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:s}),signal:AbortSignal.timeout(2e4)})
3448
3461
  if(e.ok){const t=await e.json()
3449
- t?.data?.committed&&P.info("Committed uncommitted worktree changes before completing",{requestId:s,sha:t.data.sha?.slice(0,8),files:t.data.files?.length??0})}}catch(e){P.debug("commit-worktree-leftovers unavailable; completing as before",{requestId:s,error:(0,h.getErrorMessage)(e)})}E.mainBasePath&&await(0,c.foldAtDoor)({repoDir:E.mainBasePath,branch:`requests/${s}`,defaultBranch:await(0,b.resolveDefaultBranch)(E.mainBasePath,E.gitBinary).catch(()=>"main"),requestId:s,door:"complete",gitBinary:E.gitBinary,postRecord:e=>C.proxyPost(`/api/projects/${E.projectId}/tool-records`,e),log:P})
3462
+ t?.data?.committed&&j.info("Committed uncommitted worktree changes before completing",{requestId:s,sha:t.data.sha?.slice(0,8),files:t.data.files?.length??0})}}catch(e){j.debug("commit-worktree-leftovers unavailable; completing as before",{requestId:s,error:(0,h.getErrorMessage)(e)})}E.mainBasePath&&await(0,c.foldAtDoor)({repoDir:E.mainBasePath,branch:`requests/${s}`,defaultBranch:await(0,b.resolveDefaultBranch)(E.mainBasePath,E.gitBinary).catch(()=>"main"),requestId:s,door:"complete",gitBinary:E.gitBinary,postRecord:e=>C.proxyPost(`/api/projects/${E.projectId}/tool-records`,e),log:j})
3450
3463
  let J=null,Q=null
3451
3464
  try{const e=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/branch-head?requestId=${encodeURIComponent(s)}`,{signal:AbortSignal.timeout(5e3)})
3452
3465
  if(e.ok){const t=await e.json()
3453
- J=t?.data?.sha??null,Q=t?.data?.tree??null}}catch(e){P.debug("branch-head fetch failed; server will fall back",{error:(0,h.getErrorMessage)(e)})}const Z=J?{headSha:J,...Q?{headTree:Q}:{}}:{}
3466
+ J=t?.data?.sha??null,Q=t?.data?.tree??null}}catch(e){j.debug("branch-head fetch failed; server will fall back",{error:(0,h.getErrorMessage)(e)})}const Z=J?{headSha:J,...Q?{headTree:Q}:{}}:{}
3454
3467
  let X=null
3455
3468
  try{const e=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/request-diff-stats?requestId=${encodeURIComponent(s)}`,{signal:AbortSignal.timeout(5e3)})
3456
3469
  if(e.ok){const t=await e.json()
3457
3470
  if(t?.data&&"number"==typeof t.data.additions&&"number"==typeof t.data.deletions&&"number"==typeof t.data.filesChanged){const e=Array.isArray(t.data.files)?t.data.files.filter(e=>"string"==typeof e):void 0,r=Array.isArray(t.data.deleted)?t.data.deleted.filter(e=>"string"==typeof e):void 0
3458
3471
  if(X={additions:t.data.additions,deletions:t.data.deletions,filesChanged:t.data.filesChanged,...e?{files:e}:{},docsOnly:!0===t.data.docsOnly,...r?{deleted:r}:{},..."string"==typeof t.data.branch&&t.data.branch?{branch:t.data.branch}:{}},r&&r.length>0)try{const e=await C.proxyGet(`/api/projects/${E.projectId}/test-processes`),t=Array.isArray(e)?e:Array.isArray(e?.data)?e.data:[],n=await C.getRequestClient().getRequest(s).catch(()=>null),o="string"==typeof n?.exchangeMessageCode&&n.exchangeMessageCode?await(C.getSessionMessageClient()?.getMessage(n.exchangeMessageCode).catch(()=>null)):null
3459
- X.checkLosses=await(0,l.signoffCheckLosses)(r,t,n?{...n,askedAt:o?.createdAt??null}:null)}catch(e){P.warn("checks could not be read; the sign-off card will not name deleted files a check covered",{requestId:s,error:(0,h.getErrorMessage)(e)})}}}}catch(e){P.debug("request-diff-stats fetch failed; review scaling falls back to the full panel",{error:(0,h.getErrorMessage)(e)})}const ee=X?{diffStats:X}:{}
3472
+ X.checkLosses=await(0,l.signoffCheckLosses)(r,t,n?{...n,askedAt:o?.createdAt??null}:null)}catch(e){j.warn("checks could not be read; the sign-off card will not name deleted files a check covered",{requestId:s,error:(0,h.getErrorMessage)(e)})}}}}catch(e){j.debug("request-diff-stats fetch failed; review scaling falls back to the full panel",{error:(0,h.getErrorMessage)(e)})}const ee=X?{diffStats:X}:{}
3460
3473
  let te,re=null
3461
3474
  try{const e=await C.proxyGet(`/api/projects/${E.projectId}/requests/${s}/kind`)
3462
- re=(e?.data??e)?.kind??null}catch(e){P.debug("request kind unavailable; kind checks skipped",{error:(0,h.getErrorMessage)(e)})}try{if("writing"===re){const e=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/sibling-overlap?requestId=${encodeURIComponent(s)}`,{signal:AbortSignal.timeout(1e4)}),t=(e.ok?(await e.json())?.data??[]:[]).filter(e=>!g.DOC_PATH_RE.test(e.path))
3475
+ re=(e?.data??e)?.kind??null}catch(e){j.debug("request kind unavailable; kind checks skipped",{error:(0,h.getErrorMessage)(e)})}try{if("writing"===re){const e=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/sibling-overlap?requestId=${encodeURIComponent(s)}`,{signal:AbortSignal.timeout(1e4)}),t=(e.ok?(await e.json())?.data??[]:[]).filter(e=>!g.DOC_PATH_RE.test(e.path))
3463
3476
  if(t.length>0){const e=t.slice(0,5).map(e=>{const t=e.mine.map(e=>e[0]===e[1]?`line ${e[0]}`:`lines ${e[0]}-${e[1]}`).join(", ")
3464
3477
  return`- ${e.path} (${t}) is also changed by ${e.sibling}${e.siblingTitle?` ("${e.siblingTitle}"`:""}${e.siblingStatus?`, ${e.siblingStatus.replace(/_/g," ")})`:e.siblingTitle?")":""}`}),r=[...new Set(t.map(e=>e.sibling))]
3465
- return{content:[{type:"text",text:`Completion NOT recorded: this is a writing request, and it changes code that a sibling request is changing.\n\n${e.join("\n")}\n\nA writing request documents the product as it is. Revert those changes on your branch. If your text depends on that work, wait on it: request_operations wait-on with waitsOn: ${JSON.stringify(r)}. Do not implement it and do not delete the text that describes it.`}],isError:!0}}}}catch(e){P.debug("sibling-overlap check could not run; completion continues",{error:(0,h.getErrorMessage)(e)})}try{if("drive"===re){const e=function(e,t){const r=Array.isArray(e?.acceptanceCriteria)?e.acceptanceCriteria:[]
3478
+ return{content:[{type:"text",text:`Completion NOT recorded: this is a writing request, and it changes code that a sibling request is changing.\n\n${e.join("\n")}\n\nA writing request documents the product as it is. Revert those changes on your branch. If your text depends on that work, wait on it: request_operations wait-on with waitsOn: ${JSON.stringify(r)}. Do not implement it and do not delete the text that describes it.`}],isError:!0}}}}catch(e){j.debug("sibling-overlap check could not run; completion continues",{error:(0,h.getErrorMessage)(e)})}try{if("drive"===re){const e=function(e,t){const r=Array.isArray(e?.acceptanceCriteria)?e.acceptanceCriteria:[]
3466
3479
  if(0===r.length)return null
3467
3480
  const o=e=>String(e??"").trim().toLowerCase(),s=new Set((Array.isArray(t?.couldNotCheck)?t.couldNotCheck:[]).map(o).filter(Boolean)),i=new Set((t?.commentedKeys??[]).map(o).filter(Boolean)),a=(e,t)=>e?.id?(0,n.criterionShortKey)(String(e.id),t):"",c=r.filter((e,t)=>{if((0,n.isUserOwnCheck)(e))return!1
3468
3481
  const r=(0,n.latestRow)(e,["driver"])?.verdict
@@ -3482,68 +3495,68 @@ const r=(0,n.criterionShortKey)(String(e.id),t).toLowerCase()
3482
3495
  if(!s.includes(r))return
3483
3496
  const i=(o??[]).find(e=>String(e?.key??"").trim().toLowerCase()===r)
3484
3497
  c.push({criterionId:String(e.id),reason:i?.comment??null})}),c}(C.getRequestClient(),s,z,N)
3485
- t.length>0&&await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/drive-not-checked`,{items:t})}}catch(e){P.debug("drive-claim stamp check could not run; completion continues",{error:(0,h.getErrorMessage)(e)})}const ne=[]
3498
+ t.length>0&&await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/drive-not-checked`,{items:t})}}catch(e){j.debug("drive-claim stamp check could not run; completion continues",{error:(0,h.getErrorMessage)(e)})}const ne=[]
3486
3499
  if(N&&N.length>0)try{const e=C.getRequestClient(),t=await e.getRequest(s),r=t?.acceptanceCriteria||[]
3487
- if(P.info("Recording coder criteria comments",{requestId:s,comments:N.length,criteriaFetched:r.length}),0===r.length)return P.error("Criteria comments provided but the request came back with no criteria",{requestId:s}),{content:[{type:"text",text:`Completion NOT recorded: your criteria comments could not be attached because ${s} came back with no acceptance criteria. This is a read failure on our side, not a mistake in your call. Retry complete once; if it repeats, report it to your parent as blocked and say the criteria read is failing.`}],isError:!0}
3500
+ if(j.info("Recording coder criteria comments",{requestId:s,comments:N.length,criteriaFetched:r.length}),0===r.length)return j.error("Criteria comments provided but the request came back with no criteria",{requestId:s}),{content:[{type:"text",text:`Completion NOT recorded: your criteria comments could not be attached because ${s} came back with no acceptance criteria. This is a read failure on our side, not a mistake in your call. Retry complete once; if it repeats, report it to your parent as blocked and say the criteria read is failing.`}],isError:!0}
3488
3501
  {const e=(0,p.buildCriteriaKeyMap)(r),n=[],o=[]
3489
3502
  for(const t of N){const r=e.get(t.key),s=Array.isArray(t.verify)?t.verify.filter(e=>"string"==typeof e&&e.trim()):[]
3490
3503
  if(r&&s.length>0&&"subjective"===r.kind){n.push({criterionId:r.id,evidence:`${t.comment}\n\nWhat I ran (a judgment decides this criterion, not these): ${s.join(" ; ")}`})
3491
3504
  continue}const i=s.length&&Array.isArray(t.testFiles)?t.testFiles.filter(e=>"string"==typeof e&&e.trim()).map(e=>e.trim().replace(/^\.\//,"")):[]
3492
- r?n.push({criterionId:r.id,evidence:t.comment,...s.length?{verify:s}:{},...i.length?{testFiles:i}:{}}):o.push(t.key)}if(o.length>0){const e=(0,p.formatCriteriaWithKeys)(r)
3493
- return P.warn("criteriaComments keys did not match any criterion",{requestId:s,unmatched:o}),{content:[{type:"text",text:`Completion NOT recorded: ${o.length} criteriaComments key(s) match no criterion on ${s}: ${o.join(", ")}.\n\nThe key's letter is a checksum over the criterion's id, so a wrong letter is refused rather than guessed at -- otherwise your evidence would attach to the wrong criterion. Copy the keys exactly as listed:\n\n${e}\n\nRe-run complete with the exact keys. Nothing was recorded, so no verdict was attached to the wrong criterion.`}],isError:!0}}const i=[]
3505
+ r?n.push({criterionId:r.id,evidence:t.comment,...s.length?{verify:s}:{},...i.length?{testFiles:i}:{}}):o.push(t.key)}if(o.length>0)return j.warn("criteriaComments keys did not match any criterion",{requestId:s,unmatched:o}),{content:[{type:"text",text:`Completion NOT recorded: ${o.length} criteriaComments key(s) match no criterion on ${s}: ${o.map(e=>JSON.stringify(String(e).slice(0,60))).join(", ")}.\n\nA key is the short code before each criterion, such as "1p": just those characters. The keys on ${s}:\n${(0,p.criteriaKeyChoices)(r)}\n\nRun complete again with these keys. Nothing was recorded.`}],isError:!0}
3506
+ const i=[]
3494
3507
  for(const e of n.flatMap(e=>e.verify??[])){const t=(0,m.gitVerifyProblem)(e)??(E.git?await(0,m.nodeCheckProblem)(E.git,`requests/${s}`,e):null)
3495
3508
  t&&i.push(` ${e}\n -> ${t}`)}if(E.git)for(const e of[...new Set(n.flatMap(e=>e.testFiles??[]))])await E.git.raw(["cat-file","-e",`requests/${s}:${e}`]).then(()=>!0,()=>!1)||i.push(` testFiles: ${e}\n -> no such file on ${s}'s branch; name the test files your verify commands run, as repo paths`)
3496
- if(i.length>0)return P.warn("verify commands that cannot prove anything; completion refused",{requestId:s,count:i.length}),{content:[{type:"text",text:`Completion NOT recorded: ${i.length} verify command(s) or test file(s) can never prove their criterion.\n\n${i.join("\n")}\n\nReplace them and complete again. Nothing was recorded.`}],isError:!0}
3509
+ if(i.length>0)return j.warn("verify commands that cannot prove anything; completion refused",{requestId:s,count:i.length}),{content:[{type:"text",text:`Completion NOT recorded: ${i.length} verify command(s) or test file(s) can never prove their criterion.\n\n${i.join("\n")}\n\nReplace them and complete again. Nothing was recorded.`}],isError:!0}
3497
3510
  const a=e=>{const t=r.find(t=>t?.id===e.criterionId)
3498
3511
  if((0,$.hasBaseline)(t))return[]
3499
3512
  const n="string"==typeof t?.command&&t.command.trim()?[t.command.trim()]:[],o=t?.standing&&Array.isArray(t.verify)?t.verify.filter(e=>"string"==typeof e&&!!e.trim()):n
3500
3513
  return e.verify?.length?[...o,...e.verify.filter(e=>!o.includes(e))]:[]},c=[...new Set(n.flatMap(a))]
3501
3514
  let l=null
3502
3515
  const d=function(e,t,r){return!(!t||0===r.length)&&r.every(r=>(Array.isArray(e)?e:[]).some(e=>(Array.isArray(e?.ledger)?e.ledger:[]).some(e=>"verify"===e?.source&&"met"===e?.verdict&&e?.ran===r&&"string"==typeof e?.commit&&!!e.commit&&(e.commit.startsWith(t)||t.startsWith(e.commit)))))}(r,J,c)
3503
- d&&P.info("verify preflight: every proof already passed on this head; not run again",{requestId:s,sha:J})
3516
+ d&&j.info("verify preflight: every proof already passed on this head; not run again",{requestId:s,sha:J})
3504
3517
  const u=(0,S.checksOff)(t)
3505
- if(u&&c.length>0&&P.info("verify preflight: test gate off, the worker's proofs stand as its claims; not replayed",{requestId:s,commands:c.length}),c.length>0&&!d&&!u)try{const e=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/verify-preflight`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:s,commands:c,background:!0,proofs:n.flatMap(e=>a(e).map(t=>({criterionId:e.criterionId,command:t})))}),signal:AbortSignal.timeout(18e4)}),t=e.ok?await e.json():null,r=t?.data
3506
- r?.pending&&P.info("verify preflight started beside the sign-off check; the merge waits for it",{requestId:s,sha:r.sha,commands:c.length}),r?.available&&Array.isArray(r.results)&&(l=r),r?.available&&(r.dropped??0)>0&&P.warn("verify preflight dropped commands over the ceiling",{requestId:s,dropped:r.dropped})
3518
+ if(u&&c.length>0&&j.info("verify preflight: test gate off, the worker's proofs stand as its claims; not replayed",{requestId:s,commands:c.length}),c.length>0&&!d&&!u)try{const e=await fetch(`${(0,f.getActionServerBaseUrl)()}/api/verify-preflight`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:s,commands:c,background:!0,proofs:n.flatMap(e=>a(e).map(t=>({criterionId:e.criterionId,command:t})))}),signal:AbortSignal.timeout(18e4)}),t=e.ok?await e.json():null,r=t?.data
3519
+ r?.pending&&j.info("verify preflight started beside the sign-off check; the merge waits for it",{requestId:s,sha:r.sha,commands:c.length}),r?.available&&Array.isArray(r.results)&&(l=r),r?.available&&(r.dropped??0)>0&&j.warn("verify preflight dropped commands over the ceiling",{requestId:s,dropped:r.dropped})
3507
3520
  const o=new Set(n.flatMap(e=>e.verify??[])),i=r?.available&&Array.isArray(r.results)?r.results.filter(e=>!e.ok&&!0===e.unparsed&&o.has(e.command)):[]
3508
3521
  if(i.length>0)return{content:[{type:"text",text:`Completion NOT recorded: ${i.length} of your own verify command(s) do not parse in the shell, so they never ran and prove nothing:\n\n`+i.map(e=>` ${e.command}\n -> ${e.output?e.output.split("\n")[0]:"syntax error"}`).join("\n")+"\n\nFix the command (quoting, backquotes, parentheses), then complete again. Nothing was recorded."}],isError:!0}
3509
3522
  const d=r?.available&&Array.isArray(r.results)?r.results.filter(e=>!e.ok&&(e.timedOut||e.couldNotRun)):[]
3510
- d.length>0&&P.info("verify preflight: some proofs did not finish or could not run here; the gate decides them",{requestId:s,count:d.length,sha:r?.sha})
3523
+ d.length>0&&j.info("verify preflight: some proofs did not finish or could not run here; the gate decides them",{requestId:s,count:d.length,sha:r?.sha})
3511
3524
  const u=r?.available&&Array.isArray(r.results)?r.results.filter(e=>!e.ok&&!e.timedOut&&!e.couldNotRun):[],h=u.filter(e=>!1!==(e.authoritative??r?.authoritative))
3512
- if(u.length>0&&0===h.length&&P.warn("verify preflight failed but the gate environment is ambiguous; completing anyway",{requestId:s,failed:u.length,sha:r?.sha}),h.length>0){P.warn("verify preflight failed; completion refused",{requestId:s,failed:h.length,sha:r?.sha})
3525
+ if(u.length>0&&0===h.length&&j.warn("verify preflight failed but the gate environment is ambiguous; completing anyway",{requestId:s,failed:u.length,sha:r?.sha}),h.length>0){j.warn("verify preflight failed; completion refused",{requestId:s,failed:h.length,sha:r?.sha})
3513
3526
  const e=h.map(e=>` ${e.command}\n -> exit ${e.exit}${e.timedOut?" (timed out)":""}${e.output?`: ${e.output.split("\n")[0]}`:""}`).join("\n")
3514
- return{content:[{type:"text",text:`Completion NOT recorded: ${h.length} of the criteria's verify command(s) (a criterion's own command, any a guidance check put there, and those you attached) FAIL on the tree you are completing (${String(r?.sha??"").slice(0,8)}).\n\n`+e+((r?.dropped??0)>0?`\n\n(${r.dropped} further command(s) were over the 20-command ceiling and were not run.)`:"")+"\n\nThis is the box your checks are judged in, so this is exactly what the sign-off card would show. Two things cause it: the check is wrong (it pins something you changed after writing it, such as a renamed local, or it matches by accident, such as a word found inside a longer word), or the code genuinely does not do what the criterion promises.\n\nFix whichever is wrong -- adjust a command you attached to grep the observable thing (an id, a name, an exported symbol), or fix the code -- then complete again. A criterion's own command that cannot pass where it runs: replace it by its key with request_operations update, with a line that checks what the criterion says, never less (the replacement is recorded with the line it replaced). The user's own command is not yours to replace. Nothing was recorded."}],isError:!0}}}catch(e){P.debug("verify preflight unavailable; completing without it",{requestId:s,error:(0,h.getErrorMessage)(e)})}if(n.length>0&&(await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/verify-criteria`,{verifications:n,dimension:"coder"}),ne.push(...n.map(e=>e.criterionId))),l?.sha&&l.results?.length){const e=n.flatMap(e=>a(e).flatMap(t=>{const r=l.results.find(e=>e.command===t)
3527
+ return{content:[{type:"text",text:`Completion NOT recorded: ${h.length} of the criteria's verify command(s) (a criterion's own command, any a guidance check put there, and those you attached) FAIL on the tree you are completing (${String(r?.sha??"").slice(0,8)}).\n\n`+e+((r?.dropped??0)>0?`\n\n(${r.dropped} further command(s) were over the 20-command ceiling and were not run.)`:"")+"\n\nThis is the box your checks are judged in, so this is exactly what the sign-off card would show. Two things cause it: the check is wrong (it pins something you changed after writing it, such as a renamed local, or it matches by accident, such as a word found inside a longer word), or the code genuinely does not do what the criterion promises.\n\nFix whichever is wrong -- adjust a command you attached to grep the observable thing (an id, a name, an exported symbol), or fix the code -- then complete again. A criterion's own command that cannot pass where it runs: replace it by its key with request_operations update, with a line that checks what the criterion says, never less (the replacement is recorded with the line it replaced). The user's own command is not yours to replace. Nothing was recorded."}],isError:!0}}}catch(e){j.debug("verify preflight unavailable; completing without it",{requestId:s,error:(0,h.getErrorMessage)(e)})}if(n.length>0&&(await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/verify-criteria`,{verifications:n,dimension:"coder"}),ne.push(...n.map(e=>e.criterionId))),l?.sha&&l.results?.length){const e=n.flatMap(e=>a(e).flatMap(t=>{const r=l.results.find(e=>e.command===t)
3515
3528
  return r?[{criterionId:e.criterionId,command:t,ok:r.ok,..."number"==typeof r.exit?{exit:r.exit}:{},...r.checkedNothing?{checkedNothing:r.checkedNothing}:{},...r.timedOut?{timedOut:!0}:{},...r.couldNotRun?{couldNotRun:!0}:{},output:String(r.output??"").split("\n")[0].slice(0,200)}]:[]}))
3516
- e.length>0&&await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/proof-evidence`,{commitSha:l.sha,tree:l.tree??null,proofs:e}).catch(e=>P.warn("the preflight's results were not recorded as evidence (the gate runs the proofs again)",{requestId:s,error:(0,h.getErrorMessage)(e)}))}}}catch(e){return P.error("Failed to persist coder criteria comments",{requestId:s,error:(0,h.getErrorMessage)(e)}),{content:[{type:"text",text:`Completion NOT recorded: your criteria comments could not be saved (${(0,h.getErrorMessage)(e)}). Retry complete -- without them, objective criteria stay unproven and completion is refused.`}],isError:!0}}if(E.git){try{const e=await(0,a.findCommittedMarkers)(E.git,`requests/${s}`)
3517
- if(e.determined&&e.files.length>0)return P.warn("completion refused: committed conflict markers on the branch",{requestId:s,files:e.files}),j({success:!1,reason:"unresolved_markers"}),{content:[{type:"text",text:`Completion NOT recorded: ${s}'s branch still contains committed conflict markers in ${e.files.join(", ")}.\n\nThe system merged the default branch into yours and committed the conflicted state so you could see it; those <<<<<<< / ======= / >>>>>>> lines are plain file content now. Resolve every block with your file tools, re-run your checks, then complete again.\n\nStopping here on purpose: a reviewer would only tell you the same thing a minute later.`}],isError:!0}}catch(e){P.warn("conflict-marker precheck could not run; leaving it to the merge gate",{requestId:s,error:(0,h.getErrorMessage)(e)})}if(!_.has(s))try{const e=await(0,d.scanStaleProse)(E.git,`requests/${s}`),t=(0,d.renderStaleProse)(e)
3518
- if(t)return _.add(s),P.info("completion paused once: prose the branch made stale",{requestId:s,gone:e.goneReferences.length,previewUrls:e.previewUrls.length}),j({success:!1,reason:"stale_prose_shown"}),{content:[{type:"text",text:`Completion paused for one look (${s}): your change may have made prose in the repository untrue.\n\n${t}\n\nFix what is wrong (READMEs and entry points are part of the work), then complete again. If a line is fine as it is, completing again goes straight through; this notice is shown once.`}],isError:!0}}catch(e){P.warn("stale-prose scan could not run; completing without it",{requestId:s,error:(0,h.getErrorMessage)(e)})}}let oe,se,ie=null
3529
+ e.length>0&&await C.proxyPost(`/api/projects/${E.projectId}/requests/${s}/proof-evidence`,{commitSha:l.sha,tree:l.tree??null,proofs:e}).catch(e=>j.warn("the preflight's results were not recorded as evidence (the gate runs the proofs again)",{requestId:s,error:(0,h.getErrorMessage)(e)}))}}}catch(e){return j.error("Failed to persist coder criteria comments",{requestId:s,error:(0,h.getErrorMessage)(e)}),{content:[{type:"text",text:`Completion NOT recorded: your criteria comments could not be saved (${(0,h.getErrorMessage)(e)}). Retry complete -- without them, objective criteria stay unproven and completion is refused.`}],isError:!0}}if(E.git){try{const e=await(0,a.findCommittedMarkers)(E.git,`requests/${s}`)
3530
+ if(e.determined&&e.files.length>0)return j.warn("completion refused: committed conflict markers on the branch",{requestId:s,files:e.files}),P({success:!1,reason:"unresolved_markers"}),{content:[{type:"text",text:`Completion NOT recorded: ${s}'s branch still contains committed conflict markers in ${e.files.join(", ")}.\n\nThe system merged the default branch into yours and committed the conflicted state so you could see it; those <<<<<<< / ======= / >>>>>>> lines are plain file content now. Resolve every block with your file tools, re-run your checks, then complete again.\n\nStopping here on purpose: a reviewer would only tell you the same thing a minute later.`}],isError:!0}}catch(e){j.warn("conflict-marker precheck could not run; leaving it to the merge gate",{requestId:s,error:(0,h.getErrorMessage)(e)})}if(!_.has(s))try{const e=await(0,d.scanStaleProse)(E.git,`requests/${s}`),t=(0,d.renderStaleProse)(e)
3531
+ if(t)return _.add(s),j.info("completion paused once: prose the branch made stale",{requestId:s,gone:e.goneReferences.length,previewUrls:e.previewUrls.length}),P({success:!1,reason:"stale_prose_shown"}),{content:[{type:"text",text:`Completion paused for one look (${s}): your change may have made prose in the repository untrue.\n\n${t}\n\nFix what is wrong (READMEs and entry points are part of the work), then complete again. If a line is fine as it is, completing again goes straight through; this notice is shown once.`}],isError:!0}}catch(e){j.warn("stale-prose scan could not run; completing without it",{requestId:s,error:(0,h.getErrorMessage)(e)})}}let oe,se,ie=null
3519
3532
  try{const e=await C.getRequestClient().getRequest(s),t=Array.isArray(e?.acceptanceCriteria)?e.acceptanceCriteria:[],r=t.map(e=>(0,n.latestRow)(e,["reviewer"])).filter(e=>!(!e||"met"!==e.verdict&&"unmet"!==e.verdict||"string"!=typeof e.commit||!e.commit)).sort((e,t)=>String(t.at??"").localeCompare(String(e.at??"")))[0],o=E.mainBasePath?await(0,b.resolveDefaultBranch)(E.mainBasePath):null,i=`refs/heads/requests/${s}`
3520
3533
  if(r&&E.mainBasePath&&o&&(ie=await(0,y.measureChangesSinceReview)(E.mainBasePath,{branchRef:i,reviewedSha:r.commit,defaultBranch:o,acceptedSha:"string"==typeof e?.diffSummary?.reviewAcceptedSha?e.diffSummary.reviewAcceptedSha:null}),ie&&(oe=ie.authoredCommits)),J&&E.mainBasePath&&o){const e=new Set
3521
3534
  for(const r of t){const t=(0,n.latestRow)(r,[(0,n.isUserOwnCheck)(r)?"you":"reviewer"])
3522
3535
  "met"===t?.verdict&&"string"==typeof t.commit&&t.commit&&t.commit!==J&&e.add(t.commit)}se=[]
3523
3536
  for(const t of[...e].slice(0,6)){const e=await(0,y.measureChangesSinceReview)(E.mainBasePath,{branchRef:i,reviewedSha:t,defaultBranch:o}).catch(()=>null)
3524
- se.push({sha:t,since:e?e.newLines+e.droppedLines>0?"changed":"same":"unknown"})}}}catch(e){P.debug("changes-since-review measure unavailable; the server keeps the review as it is",{error:(0,h.getErrorMessage)(e)})}if(X&&X.filesChanged>0)try{const e=await C.getRequestClient().getRequest(s)
3537
+ se.push({sha:t,since:e?e.newLines+e.droppedLines>0?"changed":"same":"unknown"})}}}catch(e){j.debug("changes-since-review measure unavailable; the server keeps the review as it is",{error:(0,h.getErrorMessage)(e)})}if(X&&X.filesChanged>0)try{const e=await C.getRequestClient().getRequest(s)
3525
3538
  if("merge"===(0,v.kindProfile)(e?.type).finalize){const t=await(0,k.closeOneTask)(C.getTaskClient(),{projectId:E.projectId,requestId:s,title:String(e?.title||s),summary:V})
3526
- t&&((0,I.clearActiveTaskCache)(),P.info("work in one piece: the request's one task closed",{requestId:s,taskId:t}))}}catch(e){P.warn("could not record the one task; completion continues as before",{requestId:s,error:(0,h.getErrorMessage)(e)})}const ae=X?.files??[]
3539
+ t&&((0,I.clearActiveTaskCache)(),j.info("work in one piece: the request's one task closed",{requestId:s,taskId:t}))}}catch(e){j.warn("could not record the one task; completion continues as before",{requestId:s,error:(0,h.getErrorMessage)(e)})}const ae=X?.files??[]
3527
3540
  let ce,le=null
3528
3541
  const de=async(e,r)=>(await Promise.resolve().then(()=>t(79414))).actionServerFetch(e,r)
3529
3542
  if(G){const e="string"==typeof W?.sitting?.head?W.sitting.head:""
3530
3543
  let t=e?null:X
3531
3544
  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=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}:{}}))
3545
+ 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){j.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
3546
  return t?.data||t}
3534
3547
  let pe=null
3535
3548
  try{if(te=await he(ce),te.canComplete&&"sitting-look"===te.plan?.action){const e=await(0,x.settleLook)(s,ae,de)
3536
3549
  pe=e.served,te=await he(e.look)}}catch(e){const t=(0,h.getErrorMessage)(e)
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`
3550
+ return j.error("Server validation failed",{requestId:s,error:t}),P({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
3551
  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
3552
  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
3553
  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: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")}]}
3554
+ 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 P({success:!1,reason:"server_blocked"}),{content:[{type:"text",text:e}],isError:!0}}if("sitting-held"===te.plan?.action)return j.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=>j.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)})),P({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
3555
  if(G&&!i)try{const e=await C.proxyGet(`/api/projects/${E.projectId}/requests/${encodeURIComponent(s)}/rounds`)
3543
3556
  V=function(e,t){const r=[]
3544
3557
  for(const t of Array.isArray(e)?e:[]){const e="string"==typeof t?.changed?t.changed.trim():""
3545
3558
  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 fe=(0,x.showGiven)(U),me=te.plan,ge="answer"===me?.action
3559
+ 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){j.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
3560
  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
3561
  const r="string"==typeof e.command?e.command.trim():""
3549
3562
  if(!r)return[]
@@ -3551,20 +3564,20 @@ const n=Array.isArray(e.ledger)?e.ledger:[]
3551
3564
  return t&&n.some(e=>"verify"===e?.source&&"string"==typeof e?.instrument&&e.instrument.startsWith("baseline")&&("met"===e.verdict||"unmet"===e.verdict)&&"string"==typeof e.commit&&!!e.commit&&(e.commit.startsWith(t)||t.startsWith(e.commit)))?[]:[{criterionId:String(e.id),command:r,baseline:e.baseline}]})}(o?.acceptanceCriteria??[],r)
3552
3565
  if(0===s.length)return
3553
3566
  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
- 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 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}
3567
+ 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,j)
3568
+ 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:j,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(()=>""):""
3569
+ if(we&&j.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 P({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
3570
  const be="testing"===me.action||"human-review"===me.action||"merge-cleared"===me.action
3558
3571
  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()
3572
+ 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){j.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
3573
  if(e){let t=new Set
3561
3574
  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
3575
  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
- 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 ve=C.getRequestClient()
3576
+ 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){j.warn("worthKnowing note failed (completion continues)",{error:(0,h.getErrorMessage)(e)})}}j.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
3577
+ 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}),j.info("guidance proposed at completion",{requestId:s})}catch(e){j.info("guidance at completion not proposed (completion continues)",{requestId:s,reason:(0,h.getErrorMessage)(e)})}const ve=C.getRequestClient()
3565
3578
  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.`}]}
3579
+ 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 P({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 P({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})
3580
+ e.refsSeen&&r?.namedRefs&&(e.refsSeen.namedRefs=r.namedRefs)}catch(e){return P({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(P({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
3581
  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
3582
  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
3583
  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.`}]}
@@ -3578,12 +3591,12 @@ try{ke=await ve.getRequest(s)}catch(e){Ie=e}const $e=(0,v.kindProfile)(re??ke?.t
3578
3591
  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
3592
  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
3593
  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})
3594
+ 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)){j.info("gates off and account recorded: merging in the same call",{requestId:s})
3582
3595
  const e=await(0,u.handleMergeRequest)({requestId:s,verifications:[]},E,C,q,T,R)
3583
3596
  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
3597
  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=""
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})
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}}}
3598
+ 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),j.error("Complete request failed",{error:r,details:n})
3599
+ try{await(0,i.createFailureToolRecord)("complete-request",t,{error:r,details:n,requestId:e?.requestId},C.getToolRecordClient(),j,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}}}
3587
3600
  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
3588
3601
  const r=t(76183),n=t(47334)
3589
3602
  exports.def={name:"create_request",description:"Create a request. delegate: true with draft has a background planner write its description and criteria from your title and this session. When it comes out of an existing record (a drive's finding, a report, a decision, another request), name that record's id in the description (\"Found by drive req000042\"): ids are the only followable trail.",schema:r.CreateRequestSchema,fieldTags:{budget:["budget"],estimate:["estimate"],scheduleDocumentId:["schedule"],questDocumentId:["schedule"],delegate:["delegate"],replaces:["refile"],asked:["asked"],process:["process"]},annotations:{title:"Create Request",readOnlyHint:!1,destructiveHint:!1},handler:(e,t)=>(0,n.handleCreateRequest)(e,t.context,t.apiClient,t.logger,t.metrics,t.mcpServer,t.cliOrigin)}},47334(e,exports,t){function r(e){return(Array.isArray(e)?e:[]).filter(e=>e&&"string"==typeof e.words&&e.words.trim()).map(e=>({description:String(e.words).trim(),kind:"measured",..."string"==typeof e.command&&e.command.trim()?{command:e.command.trim()}:{},..."string"==typeof e.metric&&e.metric.trim()?{metric:e.metric.trim()}:{},..."number"==typeof e.min?{min:e.min}:{},..."number"==typeof e.max?{max:e.max}:{},..."string"==typeof e.unit&&e.unit.trim()?{unit:e.unit.trim()}:{}}))}exports.qg=void 0,exports.handleCreateRequest=async function(e,y,w,b,v,k,I){const $=b.child({tool:"create_request"})
@@ -3619,13 +3632,13 @@ if(e){const t=await e.getByExternalId(I.sessionId)
3619
3632
  R=t?.agentType??null,"planner"!==t?.agentType&&"auto-planner"!==t?.agentType||(T=void 0,$.info("Skipping cliOrigin for planner-created request",{agentType:t.agentType}))}}catch{}R||(R=await f.sessionIdentity.getAgentTypeFor(I?.sessionId||y.currentSessionId))
3620
3633
  const A=!b.draft&&("planner"===R||"auto-planner"===R)
3621
3634
  A&&(b.draft=!0,$.info("Planner-created request filed as a draft",{agentType:R}))
3622
- const P=b.draft?"draft":"open",j=b.scheduleDocumentId||b.questDocumentId
3635
+ const j=b.draft?"draft":"open",P=b.scheduleDocumentId||b.questDocumentId
3623
3636
  let O=!1
3624
- b.planDocumentId&&j&&b.planDocumentId===j&&(b.planDocumentId=void 0,O=!0)
3637
+ b.planDocumentId&&P&&b.planDocumentId===P&&(b.planDocumentId=void 0,O=!0)
3625
3638
  let M=b.planDocumentId
3626
3639
  if(!M&&I?.sessionId)try{const e=await(0,h.getActiveSessionPlanId)(w,_,I.sessionId,$)
3627
- e&&await w.getDocumentClient().getDocument(e)&&(M=e,$.info("Auto-filled planDocumentId from session-plan association",{sessionId:I.sessionId,planDocumentId:e}))}catch(e){$.warn("planDocumentId auto-fill lookup failed (request created without plan link)",{error:(0,u.getErrorMessage)(e)})}M&&j&&M===j&&(M=void 0,O=!0)
3628
- const D=await(0,p.exchangeKeyOfCall)(y.mainBasePath,I,"string"==typeof e?.userSaid?e.userSaid:void 0),F=D?await(0,p.exchangeKeysWithCall)(y.mainBasePath,I):[],N=r(b.target),z=j?await(0,p.goalCheckOfCall)(y.mainBasePath,I):null,B={title:b.title,description:b.description||"",type:b.type,acceptanceCriteria:[...N,...b.acceptanceCriteria||[]],status:P,...M&&{planDocumentId:M},...j&&{scheduleDocumentId:j},...z&&{goalCheck:z},...b.areas&&b.areas.length>0&&{areas:b.areas},...b.waitsOn&&b.waitsOn.length>0&&{waitsOn:b.waitsOn,waitReason:String(b.waitReason).trim().slice(0,300)},...!0===b.startsNow&&{startsNow:!0},..."string"==typeof b.replaces&&b.replaces&&{replaces:b.replaces},...Array.isArray(b.asked)&&b.asked.length>0&&{asked:b.asked},...Array.isArray(b.userChoices)&&b.userChoices.length>0&&{userChoices:b.userChoices},..."string"==typeof b.process&&b.process.trim()&&{process:b.process.trim()},...void 0!==D&&{exchangeKey:D},...F.length>0&&{exchangeKeysWith:F},...T&&{cliOrigin:T},...I?.sessionId&&{creatorSessionId:I.sessionId},...b.follows&&"new"!==b.follows&&{originRequestId:String(b.follows).replace(/^(round|new):/,"")},..."string"==typeof b.follows&&b.follows.startsWith("new:")&&{ownThread:!0},..."string"==typeof b.follows&&b.follows.startsWith("round:")&&{roundOf:b.follows.slice(6)},..."number"==typeof b.budget&&{budget:b.budget,budgetSaid:"string"==typeof e?.userSaid?e.userSaid:""},...N.length>0&&"string"==typeof e?.userSaid&&{targetSaid:e.userSaid},..."number"==typeof b.estimate&&{estimate:b.estimate}}
3640
+ e&&await w.getDocumentClient().getDocument(e)&&(M=e,$.info("Auto-filled planDocumentId from session-plan association",{sessionId:I.sessionId,planDocumentId:e}))}catch(e){$.warn("planDocumentId auto-fill lookup failed (request created without plan link)",{error:(0,u.getErrorMessage)(e)})}M&&P&&M===P&&(M=void 0,O=!0)
3641
+ const D=await(0,p.exchangeKeyOfCall)(y.mainBasePath,I,"string"==typeof e?.userSaid?e.userSaid:void 0),F=D?await(0,p.exchangeKeysWithCall)(y.mainBasePath,I):[],N=r(b.target),z=P?await(0,p.goalCheckOfCall)(y.mainBasePath,I):null,B={title:b.title,description:b.description||"",type:b.type,acceptanceCriteria:[...N,...b.acceptanceCriteria||[]],status:j,...M&&{planDocumentId:M},...P&&{scheduleDocumentId:P},...z&&{goalCheck:z},...b.areas&&b.areas.length>0&&{areas:b.areas},...b.waitsOn&&b.waitsOn.length>0&&{waitsOn:b.waitsOn,waitReason:String(b.waitReason).trim().slice(0,300)},...!0===b.startsNow&&{startsNow:!0},..."string"==typeof b.replaces&&b.replaces&&{replaces:b.replaces},...Array.isArray(b.asked)&&b.asked.length>0&&{asked:b.asked},...Array.isArray(b.userChoices)&&b.userChoices.length>0&&{userChoices:b.userChoices},..."string"==typeof b.process&&b.process.trim()&&{process:b.process.trim()},...void 0!==D&&{exchangeKey:D},...F.length>0&&{exchangeKeysWith:F},...T&&{cliOrigin:T},...I?.sessionId&&{creatorSessionId:I.sessionId},...b.follows&&"new"!==b.follows&&{originRequestId:String(b.follows).replace(/^(round|new):/,"")},..."string"==typeof b.follows&&b.follows.startsWith("new:")&&{ownThread:!0},..."string"==typeof b.follows&&b.follows.startsWith("round:")&&{roundOf:b.follows.slice(6)},..."number"==typeof b.budget&&{budget:b.budget,budgetSaid:"string"==typeof e?.userSaid?e.userSaid:""},...N.length>0&&"string"==typeof e?.userSaid&&{targetSaid:e.userSaid},..."number"==typeof b.estimate&&{estimate:b.estimate}}
3629
3642
  $.info("Creating request via request client",{projectId:_,title:b.title,type:b.type,criteriaCount:b.acceptanceCriteria?.length??0})
3630
3643
  const L=await q.createRequest(B)
3631
3644
  $.debug("Create request response structure",{type:typeof L,isArray:Array.isArray(L),hasData:null!=L,properties:L?Object.keys(L):[],dataPreview:L?JSON.stringify(L).substring(0,200)+"...":"null"})
@@ -3671,7 +3684,7 @@ $.forEach(e=>{const t=e.status
3671
3684
  t in x&&x[t]++})
3672
3685
  const S=I.acceptanceCriteria||[],_=S.filter(e=>(0,c.criterionProven)(e)).length
3673
3686
  let E=I.testVerification||null
3674
- const C=I.title,q=I.type,T=I.status,R=new Date(I.createdAt).toLocaleString(),A=new Date(I.updatedAt).toLocaleString(),P=(0,r.kindProfile)(q).label,j=["canceled","reverted","completed"].includes(String(T))&&I.completionSummary?`${"completed"===T?"Outcome":"Why it ended"}: ${String(I.completionSummary).slice(0,600)}\n`:""
3687
+ const C=I.title,q=I.type,T=I.status,R=new Date(I.createdAt).toLocaleString(),A=new Date(I.updatedAt).toLocaleString(),j=(0,r.kindProfile)(q).label,P=["canceled","reverted","completed"].includes(String(T))&&I.completionSummary?`${"completed"===T?"Outcome":"Why it ended"}: ${String(I.completionSummary).slice(0,600)}\n`:""
3675
3688
  let O=""
3676
3689
  if(["canceled","cancelled","reverted"].includes(String(T))&&"request"===(0,r.kindProfile)(q).branch)try{const e=t?.mainBasePath||t?.basePath
3677
3690
  if(!e)throw new Error("no repository")
@@ -3683,8 +3696,10 @@ const t=e,r="user"===t.by?"the user":"workflow"===t.by?"the workflow":"agent"===
3683
3696
  if(!r)return""
3684
3697
  const n=t.at&&!Number.isNaN(Date.parse(t.at))?`${new Date(t.at).toLocaleString()} `:""
3685
3698
  return`${t.discarded?"Discarded":"Canceled"}: ${n}by ${r}${t.via?`, with ${t.via}`:""}`}(I.canceledBy):""
3686
- let F=`# ${P} Request: ${C} (${s})\nStatus: ${T}${I.endedWithout?`, ended without ${I.endedWithout}`:""}\n${j}${O}Created: ${R}${M?`\n${M}`:""}${D?`\n${D}`:""}\nUpdated: ${A}\n\n## Description\n${I.description||"_No description provided._"}\n\n## Progress Summary\n- Tasks: ${x.completed}/${x.total} completed (${Math.round(x.completed/x.total*100)||0}%)\n- Acceptance Criteria: ${_}/${S.length} proven (${Math.round(_/S.length*100)||0}%)\n`
3687
- F+=`\n## Task Status\n- Pending: ${x.pending}\n- In Progress: ${x.in_progress}\n- Blocked: ${x.blocked}\n- Ready for Review: ${x.ready_for_review}\n- Completed: ${x.completed}\n- Reverted: ${x.reverted}\n`,F+="\n## Tasks\n",0===$.length?F+="No tasks found for this request.\n":$.forEach(e=>{F+=`**[${e.id}]** ${e.title} (Status: ${e.status})\n`}),y.info(`Added task listing with ${$.length} tasks`),F+="\n## Acceptance Criteria\n",F+=(0,c.formatCriteriaWithHashes)(S)+"\n","ready_for_review"===I.status&&S.some(e=>!(0,c.criterionProven)(e))&&(F+="\n> **Status: ready_for_review**: Use the merge operation to verify criteria and merge to main.\n")
3699
+ let F=`# ${j} Request: ${C} (${s})\nStatus: ${T}${I.endedWithout?`, ended without ${I.endedWithout}`:""}\n${P}${O}Created: ${R}${M?`\n${M}`:""}${D?`\n${D}`:""}\nUpdated: ${A}\n\n## Description\n${I.description||"_No description provided._"}\n\n## Progress Summary\n- Tasks: ${x.completed}/${x.total} completed (${Math.round(x.completed/x.total*100)||0}%)\n- Acceptance Criteria: ${_}/${S.length} proven (${Math.round(_/S.length*100)||0}%)\n`
3700
+ F+=`\n## Task Status\n- Pending: ${x.pending}\n- In Progress: ${x.in_progress}\n- Blocked: ${x.blocked}\n- Ready for Review: ${x.ready_for_review}\n- Completed: ${x.completed}\n- Reverted: ${x.reverted}\n`,F+="\n## Tasks\n",0===$.length?F+="No tasks found for this request.\n":$.forEach(e=>{F+=`**[${e.id}]** ${e.title} (Status: ${e.status})\n`}),y.info(`Added task listing with ${$.length} tasks`)
3701
+ const N="string"==typeof I.roundOf&&I.roundOf?I.roundOf:null
3702
+ F+=N&&"completed"!==I.status?`\n## ${N}'s criteria (met when it completed)\nAn answer needs nothing more. If you change the project, your completion accounts for these again, on your change.\n`:"\n## Acceptance Criteria\n",F+=(N&&"completed"!==I.status?(0,c.formatCriteriaWithHashes)(S).replace(/\[UNPROVEN\] /g,""):(0,c.formatCriteriaWithHashes)(S))+"\n","ready_for_review"===I.status&&S.some(e=>!(0,c.criterionProven)(e))&&(F+="\n> **Status: ready_for_review**: Use the merge operation to verify criteria and merge to main.\n")
3688
3703
  try{const e=await f.proxyGet(`/api/projects/${t.projectId}/requests/${s}/record-for-agents`),r=String((e?.data??e)?.text??"").trim()
3689
3704
  r&&(F+=`\n${r}\n`)}catch(e){y.debug("record for agents unavailable",{error:(0,a.getErrorMessage)(e)})}if(E&&(F+=`\n## Test Coverage\n- Test Cases: ${E.totalTestCases||0}\n- Criteria Tested: ${E.criteriaTestedCount||0}/${S.length}\n`,E.criterionCoverage&&Array.isArray(E.criterionCoverage)&&(F+="\n### Detailed Test Coverage:\n",E.criterionCoverage.forEach(e=>{F+=`- Criterion ${e.criterionId}: ${e.coverage} coverage\n`}))),!["completed","reverted","canceled","cancelled","draft"].includes(String(T)))try{const e=await f.proxyGet(`/api/projects/${t.projectId}/requests/${s}/sessions`),r=Array.isArray(e)?e:e?.data??[]
3690
3705
  if(r.length>0){const e=await(0,d.getServerUrl)(t,y).catch(()=>null),n=await(0,l.readLiveWorker)(e??null,r)
@@ -3789,7 +3804,7 @@ Array.isArray(r.userParks)&&(e=r.userParks.filter(e=>"string"==typeof e?.code))}
3789
3804
  if(q.length>0)try{const e=(0,y.buildCriteriaKeyMap)(d?.acceptanceCriteria??[]),t=[],r=[]
3790
3805
  for(const n of q){const o=e.get(n.key)
3791
3806
  o?t.push({criterionId:o.id,evidence:n.evidence}):r.push(n.key)}r.length>0&&_.warn("merge_request: verification keys did not match any criterion (dropped)",{requestId:C,unmatched:r}),t.length>0&&(await $.proxyPost(`/api/projects/${I.projectId}/requests/${C}/verify-criteria`,{verifications:t,dimension:"coder"}),_.info("Criteria verified",{requestId:C,count:t.length}))}catch(e){const t=(0,u.getErrorMessage)(e)
3792
- _.warn("Criteria verification failed, continuing with merge",{requestId:C,error:t})}let x,S,P
3807
+ _.warn("Criteria verification failed, continuing with merge",{requestId:C,error:t})}let x,S,j
3793
3808
  try{const e=await $.proxyPost(`/api/projects/${I.projectId}/requests/${C}/validate-completion`,(0,k.validateCompletionBody)("merge"))
3794
3809
  x=e?.data||e}catch(e){const t=(0,u.getErrorMessage)(e)
3795
3810
  return E({success:!1,error:"validation_failed"}),{content:[{type:"text",text:`Failed to validate merge: ${t}`}],isError:!0}}if(!x.canComplete){let e=`Cannot merge request ${C}: ${x.reason}\n`
@@ -3798,7 +3813,7 @@ try{const e=I.workspaceManager.getCurrentContext(I.currentSessionId)?.basePath||
3798
3813
  S=(await t.raw(["merge-base",r,`requests/${C}`])).trim()||void 0
3799
3814
  const n=await(0,h.countCommitsAhead)(t,r,`requests/${C}`),o=(0,h.emptyBranchBlockMessage)(n,C,r)
3800
3815
  if(o)return E({success:!1,reason:"empty_branch"}),{content:[{type:"text",text:o}],isError:!0}
3801
- if(await(0,h.branchAddsNoContent)(t,r,`requests/${C}`))return E({success:!1,reason:"identical_tree"}),{content:[{type:"text",text:(0,h.identicalTreeBlockMessage)(C,r)}],isError:!0}}catch(e){_.warn("Could not compute merge-base / ahead count; proceeding (the merge path surfaces a real branch error)",{requestId:C,error:(0,u.getErrorMessage)(e)})}let j="workspace-manager"
3816
+ if(await(0,h.branchAddsNoContent)(t,r,`requests/${C}`))return E({success:!1,reason:"identical_tree"}),{content:[{type:"text",text:(0,h.identicalTreeBlockMessage)(C,r)}],isError:!0}}catch(e){_.warn("Could not compute merge-base / ahead count; proceeding (the merge path surfaces a real branch error)",{requestId:C,error:(0,u.getErrorMessage)(e)})}let P="workspace-manager"
3802
3817
  const O=await e.getRequest(C),M=O?.title||`Request ${C}`
3803
3818
  let D="main"
3804
3819
  try{D=await(0,w.resolveDefaultBranch)(I.mainBasePath,I.gitBinary)}catch{}const F=I.git?await(0,c.findCommittedMarkers)(I.git,`requests/${C}`):{files:[],determined:!1}
@@ -3826,15 +3841,15 @@ if("sent-back"===e.action)return E({success:!1,error:"sent_back"}),await(0,m.bri
3826
3841
  if("review-held"===e.action){E({success:!1,error:"review_held"})
3827
3842
  const t=await(0,m.holdForMainChangeReview)({projectPath:T,projectId:I.projectId,requestId:C,defaultBranch:D,touched:e.touched,logger:_,post:(e,t)=>$.proxyPost(e,t)})
3828
3843
  return{content:[{type:"text",text:`Not merged yet: ${e.summary}\n\n${t.reviewing?`Main's newer work is now on your branch, and a reviewer is checking ${C}'s criteria against that change. Wait for its report: apply what it asks for, then complete again.`:"A review of that change could not be started; make sure your work holds alongside main's newer work, then merge again."}`}],isError:!0}}"conflicts"===e.action&&(z=new Error(`Merge of requests/${C} into ${D} has conflicts (detected on the prospective merge tree):\n${e.summary}`),z.conflictInfo={conflictedFiles:[],workingDirectory:void 0}),"land"===e.action&&(N=e.certifiedCommitSha,_.info("merge-queue: landing certified catch-up commit (tested tree == merged tree)",{requestId:C,certifiedCommitSha:N.slice(0,8)}))}try{if(z)throw z
3829
- P=await I.workspaceManager.completeRequest(C,M,N?{certifiedCommitSha:N}:void 0),j=N?"merge-queue-certified":P.autoMergeInfo?.strategy||"workspace-manager",_.info("Merge completed",{requestId:C,mergeCommitHash:P.mergeCommitHash,mergeMethod:j})}catch(t){if(!t.conflictInfo){const e=(0,u.getErrorMessage)(t)
3844
+ j=await I.workspaceManager.completeRequest(C,M,N?{certifiedCommitSha:N}:void 0),P=N?"merge-queue-certified":j.autoMergeInfo?.strategy||"workspace-manager",_.info("Merge completed",{requestId:C,mergeCommitHash:j.mergeCommitHash,mergeMethod:P})}catch(t){if(!t.conflictInfo){const e=(0,u.getErrorMessage)(t)
3830
3845
  return E({success:!1,error:"merge_failure"}),{content:[{type:"text",text:`Merge failed: ${e}`}],isError:!0}}{const r=t.conflictInfo.workingDirectory||I.workspaceManager?.getCurrentContext(I.currentSessionId)?.basePath||void 0,n=`requests/${C}`,o=await(0,c.reconcileBranchWithMain)({projectPath:I.basePath,requestId:C,branchName:n,defaultBranch:D,worktreePath:r})
3831
3846
  if("clean"!==o.outcome){if("conflicts-committed"===o.outcome){try{await e.updateRequest(C,{status:"resolving_conflicts"}),_.info("Set status to resolving_conflicts",{requestId:C})}catch(e){_.error("Failed to set resolving_conflicts status",{requestId:C,error:(0,u.getErrorMessage)(e)})}const t=(0,c.buildResolveInstruction)({requestId:C,branchName:n,defaultBranch:D,landed:o.landed,conflictedFiles:o.conflictedFiles,blocks:o.blocks,keptBoth:o.keptBoth,retryVia:"merge"})
3832
3847
  return E({success:!1,reason:"merge_conflicts"}),{content:[{type:"text",text:t}],isError:!1}}return E({success:!1,reason:"merge_conflicts"}),{content:[{type:"text",text:`${C} conflicts with ${D}, and ${D} could not be brought into its branch: ${(0,c.reconcileRefusal)(o)}. Fix that, then merge again.`}],isError:!0}}_.info("Branch reconciled with main cleanly: retrying merge",{requestId:C})
3833
- try{P=await I.workspaceManager.completeRequest(C,M),j="reconcile-retry"}catch(e){return E({success:!1,error:"merge_failure_after_reconcile"}),{content:[{type:"text",text:`Merge failed after clean reconcile: ${(0,u.getErrorMessage)(e)}`}],isError:!0}}}}const B=I.workspaceManager.getCurrentContext(I.currentSessionId)?.basePath||I.basePath,L=N??P?.mergeCommitHash
3848
+ try{j=await I.workspaceManager.completeRequest(C,M),P="reconcile-retry"}catch(e){return E({success:!1,error:"merge_failure_after_reconcile"}),{content:[{type:"text",text:`Merge failed after clean reconcile: ${(0,u.getErrorMessage)(e)}`}],isError:!0}}}}const B=I.workspaceManager.getCurrentContext(I.currentSessionId)?.basePath||I.basePath,L=N??j?.mergeCommitHash
3834
3849
  L&&(S=await(0,i.firstParentSha)((0,i.gitFor)(B,I.git,I.gitBinary),L)??S)
3835
- const H=await(0,i.computeDiffStats)((0,i.gitFor)(B,I.git,I.gitBinary),S,P?.mergeCommitHash),U=L&&(0,n.checksOff)(O)?await(0,b.landedOnTopOf)(B,L,C).catch(()=>[]):[]
3836
- try{await $.proxyPost(`/api/projects/${I.projectId}/requests/${C}/finalize-completion`,{summary:O?.completionSummary||`Merged request ${C}`,mergeResult:{mergeCommitHash:P.mergeCommitHash,mergeBaseSha:S,mergedFiles:P.mergedFiles,cleanedUp:P.cleanedUp,method:j,diffStats:H,...U.length?{notCheckedWith:U}:{}}})}catch(e){const t=(0,u.getErrorMessage)(e)
3837
- return _.error("CRITICAL: Merge succeeded but server finalization failed",{requestId:C,mergeCommitHash:P.mergeCommitHash,error:t}),E({success:!1,error:"api_update_failed"}),{content:[{type:"text",text:`CRITICAL: Code was merged (commit: ${P.mergeCommitHash.substring(0,8)}) but failed to update server: ${t}`}],isError:!0}}return(0,o.maybePublishReceiptOnMerge)(C),(0,g.clearMergeCandidate)(T,C,I.gitBinary).catch(()=>{}),E({success:!0}),{content:[{type:"text",text:`Request ${C} merged successfully.\nCommit: ${P.mergeCommitHash.substring(0,8)}`}]}}catch(e){const t=(0,u.getErrorMessage)(e)
3850
+ const H=await(0,i.computeDiffStats)((0,i.gitFor)(B,I.git,I.gitBinary),S,j?.mergeCommitHash),U=L&&(0,n.checksOff)(O)?await(0,b.landedOnTopOf)(B,L,C).catch(()=>[]):[]
3851
+ try{await $.proxyPost(`/api/projects/${I.projectId}/requests/${C}/finalize-completion`,{summary:O?.completionSummary||`Merged request ${C}`,mergeResult:{mergeCommitHash:j.mergeCommitHash,mergeBaseSha:S,mergedFiles:j.mergedFiles,cleanedUp:j.cleanedUp,method:P,diffStats:H,...U.length?{notCheckedWith:U}:{}}})}catch(e){const t=(0,u.getErrorMessage)(e)
3852
+ return _.error("CRITICAL: Merge succeeded but server finalization failed",{requestId:C,mergeCommitHash:j.mergeCommitHash,error:t}),E({success:!1,error:"api_update_failed"}),{content:[{type:"text",text:`CRITICAL: Code was merged (commit: ${j.mergeCommitHash.substring(0,8)}) but failed to update server: ${t}`}],isError:!0}}return(0,o.maybePublishReceiptOnMerge)(C),(0,g.clearMergeCandidate)(T,C,I.gitBinary).catch(()=>{}),E({success:!0}),{content:[{type:"text",text:`Request ${C} merged successfully.\nCommit: ${j.mergeCommitHash.substring(0,8)}`}]}}catch(e){const t=(0,u.getErrorMessage)(e)
3838
3853
  _.error("Merge request failed",{error:t})
3839
3854
  try{await(0,d.createFailureToolRecord)("merge-request",e,{error:t,requestId:C},$.getToolRecordClient(),_,S,{requestId:C,projectId:I.projectId,note:"Failed to merge request"})}catch{}return E({success:!1,error:e instanceof Error?e.name:"unknown"}),{content:[{type:"text",text:`Error: ${t}`}],isError:!0}}finally{if(R&&!A)try{(0,p.releaseMergeLease)(T,C)}catch{}}}
3840
3855
  const n=t(64721),o=t(19817),s=t(83807),i=t(92456),a=t(59860),c=t(35510),l=t(82860),d=t(18616),u=t(58824),h=t(27478),p=t(56509),f=t(14128),m=t(13922),g=t(87192),y=t(65454),w=t(52232),b=t(82865),v=t(87780),k=t(63580),I={"signoff-park":"the sign-off","test-process-broken":"a test check that cannot run","test-cap-escalation":"tests that keep failing","review-cap-escalation":"review findings still open","review-gap":"a review that did not run","environment-gap":"the test box missing a tool","unprovable-criteria":"criteria nothing can prove"}},95765(e,exports){exports.ownRequestResult=function(e,t,r,n=""){return`${e} is a request of its own now${t?`, no longer a round of ${t}`:""}: "${r}".${n?` The user has been told ("${n}").`:""} It keeps this working copy and you, and what you changed on it stays with it. It has no criteria of its own yet${t?` (the ones it carried were ${t}'s and are gone)`:""}: write what this work must do (request_operations update, acceptanceCriteria), then build it and complete it as any request.`}},95994(e,exports,t){var r,n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
@@ -4354,13 +4369,13 @@ try{E=(await p.default.stat(S)).isFile()}catch(e){const t=`Cannot access path ${
4354
4369
  throw x.errors.push(t),new Error(t)}const C=f.maxResults||50,q=f.caseSensitive||!1
4355
4370
  let T=!1!==f.useRegex
4356
4371
  if(T)try{new RegExp(e)}catch{T=!1}const R=f.fileExtension,A=f.searchIn||"content"
4357
- let P=void 0!==f.contextLines?f.contextLines:0
4358
- P<0?P=0:P>10&&(d.warn(`contextLines ${P} exceeds maximum of 10, clamping to 10`),P=10)
4359
- let j,O=""
4372
+ let j=void 0!==f.contextLines?f.contextLines:0
4373
+ j<0?j=0:j>10&&(d.warn(`contextLines ${j} exceeds maximum of 10, clamping to 10`),j=10)
4374
+ let P,O=""
4360
4375
  if(E)O="*"
4361
4376
  else if(R&&"*"!==R){if(R){let e=R;(e.startsWith("*.")||e.startsWith("*"))&&(e=e.substring(1)),O=e.startsWith(".")?e:`.${e}`}}else O="*"
4362
- try{j=T?q?new RegExp(e):new RegExp(e,"i"):q?new RegExp(o(e)):new RegExp(o(e),"i")}catch(e){const t=`Invalid ${T?"regex":"search"} pattern: ${(0,k.getErrorMessage)(e)}`
4363
- throw x.errors.push(t),(0,m.createValidationError)(t)}if(x.patternInfo={needle:e,regex:j.toString(),caseSensitive:q,fileExtension:R,normalizedExtension:O},!E)try{const e=Date.now(),t=await p.default.readdir(S,{withFileTypes:!0}),r=[],n=[]
4377
+ try{P=T?q?new RegExp(e):new RegExp(e,"i"):q?new RegExp(o(e)):new RegExp(o(e),"i")}catch(e){const t=`Invalid ${T?"regex":"search"} pattern: ${(0,k.getErrorMessage)(e)}`
4378
+ throw x.errors.push(t),(0,m.createValidationError)(t)}if(x.patternInfo={needle:e,regex:P.toString(),caseSensitive:q,fileExtension:R,normalizedExtension:O},!E)try{const e=Date.now(),t=await p.default.readdir(S,{withFileTypes:!0}),r=[],n=[]
4364
4379
  for(const e of t)e.isDirectory()?r.push(e.name):e.isFile()&&n.push(e.name)
4365
4380
  x.initialScan={totalEntries:t.length,directories:r,files:n,firstFewFiles:n.slice(0,10),scanTime:Date.now()-e},x.phases.directoryListingTime=x.initialScan.scanTime}catch(e){const t=`Failed to scan directory contents: ${(0,k.getErrorMessage)(e)}`
4366
4381
  x.errors.push(t),d.error(t)}const M=E?"file":"directory"
@@ -4382,7 +4397,7 @@ o.errors.push(r),n.error(r)}return{matches:i,totalFiles:1}}(e,t,d,s,i,f)
4382
4397
  const g={path:e,filesProcessed:0,filesMatched:0,subdirectories:0,errors:[]}
4383
4398
  try{const n=a||e,l=await(0,b.gitVisibleFilter)(n),{filesCount:u,fileMatchesCount:h,subdirCount:p,subdirStats:y}=await r(e,t,m,c,o,s,0,g,d,f,a,l?{filter:l,root:n}:void 0)
4384
4399
  return g.filesProcessed=u,g.filesMatched=h,g.subdirectories=p,i.directoryStats.push(g),y&&y.length>0&&i.directoryStats.push(...y),s.info("performLocalSearch completed",{totalFiles:u,matchesFound:m.length,directories:p+1}),{matches:m,totalFiles:u}}catch(t){const r=`Error in performLocalSearch: ${(0,k.getErrorMessage)(t)}`
4385
- return g.errors.push(r),i.directoryStats.push(g),i.errors.push(r),s.error(r,{error:t instanceof Error?t.stack:String(t),searchPath:e}),{matches:m,totalFiles:g.filesProcessed}}}(S,j,{maxResults:C,fileExtension:O,searchIn:A,isFile:E,contextLines:P},O,d,x,_)
4400
+ return g.errors.push(r),i.directoryStats.push(g),i.errors.push(r),s.error(r,{error:t instanceof Error?t.stack:String(t),searchPath:e}),{matches:m,totalFiles:g.filesProcessed}}}(S,P,{maxResults:C,fileExtension:O,searchIn:A,isFile:E,contextLines:j},O,d,x,_)
4386
4401
  F=e.matches,N=e.totalFiles
4387
4402
  const t=1e3
4388
4403
  F.length>0&&F.length<=t?(F.sort((e,t)=>void 0!==e.modifiedTime&&void 0!==t.modifiedTime?t.modifiedTime-e.modifiedTime:void 0!==e.modifiedTime&&void 0===t.modifiedTime?-1:void 0===e.modifiedTime&&void 0!==t.modifiedTime?1:0),d.info(`Sorted ${F.length} matches by modification time (newest first)`)):F.length>t&&d.info(`Skipped sorting ${F.length} matches (exceeds hard cap of ${t} for performance)`),z=F.length,F.length>C&&(F=F.slice(0,C),d.info(`Limited results to ${C} (from ${z} total matches)`)),F.forEach(e=>{e.relativePath=function(e,t){const r=h.default.relative(e,t)
@@ -4392,7 +4407,7 @@ let B,L=""
4392
4407
  try{if(n.workspaceManager){const e=n.workspaceManager.getCurrentContext(n.currentSessionId)
4393
4408
  e.branchName&&!e.permanentBranch&&(L=e.isMainBranch?` (searched on main branch: ${e.branchName})`:` (searched on request branch: ${e.branchName}${e.requestId?` for ${e.requestId}`:""})`)}}catch(e){d.debug("Could not get branch context",{error:e}),L=" (branch context unavailable)"}d.debug("Search diagnostic information",{diagnostic:x})
4394
4409
  const H="content"===A?"content":"filename"===A?"filenames":"content and filenames"
4395
- if(z>F.length?(B=`Found ${z} results for "${e}" (searching ${H})`,a&&(B+=` in ${a}`),R&&(B+=` with extension ${R}`),B+=`${L}. Showing first ${F.length}:\n\n`):(B=`Found ${F.length} results for "${e}" (searching ${H})`,a&&(B+=` in ${a}`),R&&(B+=` with extension ${R}`),B+=`${L}:\n\n`),F.length>0)if(P>0){const{filenameMatches:e,mergedGroups:t}=function(e,t){const r=e.filter(e=>"filename"===e.matchType),n=e.filter(e=>"content"===e.matchType)
4410
+ if(z>F.length?(B=`Found ${z} results for "${e}" (searching ${H})`,a&&(B+=` in ${a}`),R&&(B+=` with extension ${R}`),B+=`${L}. Showing first ${F.length}:\n\n`):(B=`Found ${F.length} results for "${e}" (searching ${H})`,a&&(B+=` in ${a}`),R&&(B+=` with extension ${R}`),B+=`${L}:\n\n`),F.length>0)if(j>0){const{filenameMatches:e,mergedGroups:t}=function(e,t){const r=e.filter(e=>"filename"===e.matchType),n=e.filter(e=>"content"===e.matchType)
4396
4411
  if(0===n.length)return{filenameMatches:r,mergedGroups:[]}
4397
4412
  const o=new Map
4398
4413
  for(const e of n){const t=o.get(e.file)||[]
@@ -4400,7 +4415,7 @@ t.push(e),o.set(e.file,t)}const i=[]
4400
4415
  for(const[e,r]of o.entries()){r.sort((e,t)=>e.line-t.line)
4401
4416
  let e=[r[0]]
4402
4417
  for(let n=1;n<r.length;n++){const o=e[e.length-1],a=r[n],c=o.line+t
4403
- a.line-t<=c+1?e.push(a):(i.push(s(e,t)),e=[a])}e.length>0&&i.push(s(e,t))}return{filenameMatches:r,mergedGroups:i}}(F,P),r=[]
4418
+ a.line-t<=c+1?e.push(a):(i.push(s(e,t)),e=[a])}e.length>0&&i.push(s(e,t))}return{filenameMatches:r,mergedGroups:i}}(F,j),r=[]
4404
4419
  e.forEach(e=>{r.push(`${e.relativePath} [filename match]`)}),t.forEach(e=>{const t=[]
4405
4420
  e.lines.forEach(e=>{e.isMatch?t.push(`> ${e.lineNumber}: ${e.content}`):t.push(` ${e.lineNumber}: ${e.content}`)}),r.push(`${e.relativePath}:\n${t.join("\n")}`)}),B+=r.join("\n\n")}else B+=await async function(e){const t=e.filter(e=>"filename"===e.matchType),r=e.filter(e=>"content"===e.matchType),n=[]
4406
4421
  t.length>0&&t.forEach(e=>{n.push(`${e.relativePath} [filename match]`)})
@@ -4501,7 +4516,7 @@ if("reply"===e){const e=t?.messageCode
4501
4516
  return"string"==typeof e&&e.startsWith("R-")?"acknowledge-report":"string"==typeof e&&e.startsWith("Q-")?"answer-question":"reply-message"}return"note"===e?!0===t?.milestone?"send-milestone":"send-note":"list"===e?"list-messages":"get"===e?"get-message":"offer-handoff"===e?"offer-handoff":"record-decision"===e?"record-decision":"brief"===e?"opening-brief":"session-message-operations"}async function n(e){return C.sessionIdentity.getAgentTypeFor(e)}async function o(e,t,r,n,o){const s=o?.alchemy,i=await(0,A.deliverToSession)(e,t,{kind:s?.kind??"inserted-prompt",...s?.payload?{partPayload:s.payload}:{}})
4502
4517
  return i.ok?(n.info("Notified session",{sessionId:e,messageId:i.messageId}),!0):(n.warn("Failed to notify session",{sessionId:e,error:i.error,detail:i.detail}),!1)}function s(e,t,r){return C.sessionIdentity.getParentSessionId(e,t,r)}function i(e,t,r,n,o){const s=o?.sessionId||C.sessionIdentity.getIdentity()?.sessionId
4503
4518
  if(!s)throw new v.ValidationError("No session identity available. Make sure you are running within an OpenCode session.")
4504
- return(0,j.logSessionIdentity)(`${r}`,"identity",{sessionId:s,fromCliOrigin:!!o?.sessionId}),s}function a(e){const t=[],r=e.content||{}
4519
+ return(0,P.logSessionIdentity)(`${r}`,"identity",{sessionId:s,fromCliOrigin:!!o?.sessionId}),s}function a(e){const t=[],r=e.content||{}
4505
4520
  t.push(`**Message Code:** ${e.messageCode}`),t.push(`**Type:** question (${r.questionType})`),t.push(`**Status:** ${e.status}`),t.push(`**Priority:** ${e.priority}`),t.push(`**From:** ${e.fromSessionId}`),t.push(e.toSessionId?`**To:** ${e.toSessionId}`:"**To:** (broadcast)"),t.push(`**Created:** ${e.createdAt}`),t.push(`**Expires:** ${e.expiresAt}`),t.push(""),t.push(`**Question:** ${r.question}`)
4506
4521
  for(const r of Array.isArray(e.guidanceNow)?e.guidanceNow:[])t.push(`**Guidance:** ${r}`)
4507
4522
  if(r.context&&t.push(`**Context:** ${r.context}`),"alternatives"===r.questionType&&r.options){t.push(""),t.push("**Options:**")
@@ -4524,10 +4539,10 @@ const E=Array.isArray(e.criteria)?[...new Set(e.criteria.map(e=>String(e).trim()
4524
4539
  E.length>0&&(delete y.defaultOption,y.onExpiry="escalate",$=!0)
4525
4540
  const C=i(0,0,"session_message_operations",0,u)
4526
4541
  let q=await async function(e,t,r,n){if("parent"===e){const e=await s(t,r,n)
4527
- return e?(n.info('Resolved toSessionId "parent" to actual ID',{parentId:e}),e):void n.warn('report toSessionId "parent" but this session has no parent; recording without a parent target',{fromSessionId:t})}return void 0===e?void 0:(0,P.asExternal)(e)}(m,C,c,r),R=!1
4542
+ return e?(n.info('Resolved toSessionId "parent" to actual ID',{parentId:e}),e):void n.warn('report toSessionId "parent" but this session has no parent; recording without a parent target',{fromSessionId:t})}return void 0===e?void 0:(0,j.asExternal)(e)}(m,C,c,r),R=!1
4528
4543
  if(q)try{const[e,t]=await Promise.all([n(C),n(q)])
4529
4544
  "planner"===e&&"alchemist"===t&&(q=void 0,R=!0)}catch{}if(!("alternatives"!==g||y.options&&Array.isArray(y.options)))throw new v.ValidationError("Not sent: an alternatives question needs questionContent.options, a list of { id, label, description } INSIDE questionContent (options anywhere else are dropped). Nothing was posted.")
4530
- let A="",j=0,D=null,F=!1,N=!1
4545
+ let A="",P=0,D=null,F=!1,N=!1
4531
4546
  if(!q){let n="balanced",o=!1
4532
4547
  try{const e=await l.getInteractionPosture(C)
4533
4548
  n=e.posture,o=!0===e.humanInputFloor}catch(e){r.warn("Question gate: posture lookup failed, defaulting to balanced",{error:(0,k.getErrorMessage)(e)})}const s="string"==typeof e.userSaid?e.userSaid:"",i=!!s&&await(0,O.userSaidOnRequest)(c,t.projectId,"",s,{anywhere:!0}).catch(()=>!1)
@@ -4544,15 +4559,15 @@ if("settled"===e.kind)return{content:[{type:"text",text:d(e.settled)}]}
4544
4559
  const t=e.message
4545
4560
  return{content:[{type:"text",text:`\u{1f4e5} **Question held for the next checkpoint** (${u.reason}).\n\n**Proceed on your default now: ${n}**\n\nIt was recorded as **${t.messageCode}** and will be presented to the user as part of the next checkpoint bundle (e.g. when a request reaches review or a plan is handed off). If it expires first it resolves to your default. If the eventual answer differs from your default you will receive a correction: fold it in then.`}]}}catch(e){r.warn("Question gate: deferred create failed, posting the question normally",{error:(0,k.getErrorMessage)(e)})}}else u.hint&&(A=`\n\n\u{1f4a1} ${u.hint}`)}const h=y.context
4546
4561
  if(!("object"==typeof h&&null!==h||"string"==typeof h&&/^[\[{]/.test(h.trim()))){const e=(0,S.resolveHoldPolicy)(n,{proceedsOnDefault:(0,S.proceedsOnDefault)({defaultOption:y.defaultOption,onExpiry:y.onExpiry,steer:y.steer,priority:w,namedCriteria:E.length})})
4547
- j=e.holdMs,D=n,F=0===j&&"balanced"===(0,S.normalizePosture)(n),j>0&&r.info("Question will sync-hold",{holdMs:j,posture:n,reason:e.reason})}}r.info("Creating question",{fromSessionId:C,toSessionId:q,questionType:g})
4548
- const z=await l.createQuestionSettleAware({fromSessionId:C,toSessionId:q,questionType:g,question:y.question,options:y.options,context:y.context,allowMultiple:y.allowMultiple,...Array.isArray(y.fields)&&y.fields.length>0?{fields:y.fields}:{},defaultOption:y.defaultOption,onExpiry:"collaborative"===D?"escalate":y.onExpiry,...y.steer?{steer:y.steer}:{},...!0===y.changeableLater?{changeableLater:!0}:{},priority:w,expiresInHours:b,...I?{relatesTo:I}:{},...j>0?{holdUntil:new Date(Date.now()+j).toISOString()}:{},...F?{proceededOnDefault:!0}:{},...N?{userAsked:!0}:{},...$?{forceAsk:!0}:{},...x,...E.length>0?{criteria:E}:{}})
4562
+ P=e.holdMs,D=n,F=0===P&&"balanced"===(0,S.normalizePosture)(n),P>0&&r.info("Question will sync-hold",{holdMs:P,posture:n,reason:e.reason})}}r.info("Creating question",{fromSessionId:C,toSessionId:q,questionType:g})
4563
+ const z=await l.createQuestionSettleAware({fromSessionId:C,toSessionId:q,questionType:g,question:y.question,options:y.options,context:y.context,allowMultiple:y.allowMultiple,...Array.isArray(y.fields)&&y.fields.length>0?{fields:y.fields}:{},defaultOption:y.defaultOption,onExpiry:"collaborative"===D?"escalate":y.onExpiry,...y.steer?{steer:y.steer}:{},...!0===y.changeableLater?{changeableLater:!0}:{},priority:w,expiresInHours:b,...I?{relatesTo:I}:{},...P>0?{holdUntil:new Date(Date.now()+P).toISOString()}:{},...F?{proceededOnDefault:!0}:{},...N?{userAsked:!0}:{},...$?{forceAsk:!0}:{},...x,...E.length>0?{criteria:E}:{}})
4549
4564
  if("settled"===z.kind)return{content:[{type:"text",text:d(z.settled)}]}
4550
4565
  const B=z.message
4551
4566
  if(!q&&"responded"===B?.status&&"self-driving"===B?.response?.settledBy)return{content:[{type:"text",text:f(B,y)}]}
4552
- if(p?.afterCreate)try{await p.afterCreate({messageCode:B.messageCode})}catch(e){r.warn("sendQuestion afterCreate hook failed (question already posted)",{code:B.messageCode,error:(0,k.getErrorMessage)(e)})}if(j>0&&!B?.content?.holdUntil){r.info("Sync-hold skipped by server (no UI client connected)",{code:B.messageCode}),j=0
4567
+ if(p?.afterCreate)try{await p.afterCreate({messageCode:B.messageCode})}catch(e){r.warn("sendQuestion afterCreate hook failed (question already posted)",{code:B.messageCode,error:(0,k.getErrorMessage)(e)})}if(P>0&&!B?.content?.holdUntil){r.info("Sync-hold skipped by server (no UI client connected)",{code:B.messageCode}),P=0
4553
4568
  const e=B.messageCode
4554
4569
  if("collaborative"===D)return{content:[{type:"text",text:`\u23f3 **Question posted as ${e}; the user is not on the page right now.** The interaction posture is collaborative: this decision stays with the user: do NOT proceed or assume a default. Wrap up your turn cleanly now; you will be automatically resumed with the answer (or a dismissal) whenever it arrives.${(0,M.namedRefsNote)(B?.content?.namedRefs)}`}]}
4555
- if(y.defaultOption)return{content:[{type:"text",text:`\u{1f4e8} **Question posted as ${e}; the user is not on the page right now.**\n\n**Proceed on your default now: ${String(y.defaultOption)}**\n\nIf the eventual answer differs, you will be resumed with a correction: fold it in then.${(0,M.namedRefsNote)(B?.content?.namedRefs)}`}]}}if(j>0){const e=B.messageCode,t=await(0,_.runSyncHold)({client:l,logger:r,messageCode:e,holdMs:j,proceededOnDefault:"collaborative"!==D&&!!y.defaultOption})
4570
+ if(y.defaultOption)return{content:[{type:"text",text:`\u{1f4e8} **Question posted as ${e}; the user is not on the page right now.**\n\n**Proceed on your default now: ${String(y.defaultOption)}**\n\nIf the eventual answer differs, you will be resumed with a correction: fold it in then.${(0,M.namedRefsNote)(B?.content?.namedRefs)}`}]}}if(P>0){const e=B.messageCode,t=await(0,_.runSyncHold)({client:l,logger:r,messageCode:e,holdMs:P,proceededOnDefault:"collaborative"!==D&&!!y.defaultOption})
4556
4571
  if("answered"===t.kind)return{content:[{type:"text",text:`\u2705 **Answered while you waited.**\n\n${a(t.message)}\n\nContinue based on this answer now.${(0,M.namedRefsNote)(B?.content?.namedRefs)}`}]}
4557
4572
  let n
4558
4573
  return n="expired"===t.kind?`\u23f3 **The question expired unanswered** (**${e}**). Decide yourself now: pick the best option, record it with the record-decision operation, and proceed. No automatic resume will come for this question.`:"collaborative"===D?`\u23f3 **No answer yet.** The interaction posture is collaborative: this decision stays with the user: do NOT proceed or assume a default. Wrap up your turn cleanly now; the question remains open as **${e}** and you will be automatically resumed with the answer (or a dismissal) whenever it arrives.`:y.defaultOption?`\u23f3 **No answer within the hold window.** The question stays open as **${e}** (inbox).\n\n**Proceed on your default now: ${String(y.defaultOption)}**\n\nIf the eventual answer differs, you will be resumed with a correction: fold it in then.`:`\u23f3 **No answer within the hold window** and no default was stated. **Decide yourself now**: pick the best option, record it with the record-decision operation (so the user can review or correct it later), and proceed. The question stays open as **${e}**; if the user answers later you will be resumed: treat it as confirmation or a correction.`,{content:[{type:"text",text:n+(0,M.namedRefsNote)(B?.content?.namedRefs)}]}}if(F)return{content:[{type:"text",text:`\u2705 Question posted as **${B.messageCode}**. It goes ahead on its default, so nothing waits for it.\n\n**Proceed on your default now: ${String(y.defaultOption)}**\n\nIf the user answers differently, you will be resumed with a correction: fold it in then.${A}${(0,M.namedRefsNote)(B?.content?.namedRefs)}`}]}
@@ -4600,13 +4615,13 @@ if(w.cards.length>0){await s.createReport({fromSessionId:t,status:"blocked",atte
4600
4615
  let r=!0
4601
4616
  try{await o.proxyPatch(`/api/projects/${a}/cli-sessions/${encodeURIComponent(t)}`,{waitingOn:{kind:"card",messageCodes:w.cards,requestId:c,since:(new Date).toISOString()}})}catch(e){r=!1,n.warn("blocked on a card: the wait was not declared",{sessionId:t,requestId:c,cards:w.cards,error:(0,k.getErrorMessage)(e)})}return{content:[{type:"text",text:r?`\u23f3 Wait declared on the user's open card ${w.cards.join(", ")} on ${c}; your words were posted beside it. No second question was filed. You are resumed with the answer when it is settled. End your turn now.`:`\u{1f4ec} Posted to the user on ${c}, beside their open card ${w.cards.join(", ")}; no second question was filed. The wait could not be recorded. End your turn.`}]}}const b={toSessionId:"parent",questionType:"free-form",priority:"high",expiresInHours:1,questionContent:{question:`${c} is blocked on a decision: ${String(e.summary).slice(0,400)}`,context:`[blocked on a decision, from the worker of ${c}] ${String(e.details??"").slice(0,1500)}\n\nIf you cannot decide this, do not acknowledge it: let it escalate to the user.`,onExpiry:"escalate"}},v=await m({...b,requestId:c,forceAsk:!0,keepsOpen:!0},r,n,o,s,i)
4602
4617
  return{...v,content:[...v.content,{type:"text",text:"\n\n\u23f8 Filed as a QUESTION to your parent (a registered wait), not a report: it must be answered, and it escalates to the user if the parent cannot. You will get the answer as a message. Meanwhile work on anything not blocked, then end your turn."}]}}(e,_,r,a,c,d,u)
4603
- if(t)return t}}const j=await(async()=>{if(e.toSessionId&&"parent"!==e.toSessionId)return a.info("Using explicit toSessionId for report",{parentSessionId:e.toSessionId}),(0,P.asExternal)(e.toSessionId)
4618
+ if(t)return t}}const P=await(async()=>{if(e.toSessionId&&"parent"!==e.toSessionId)return a.info("Using explicit toSessionId for report",{parentSessionId:e.toSessionId}),(0,j.asExternal)(e.toSessionId)
4604
4619
  if("parent"===e.toSessionId)return await s(_,c,a)||void a.warn('toSessionId "parent" but no parent is recorded; filing target-less',{sessionId:_})
4605
4620
  const t=await s(_,c,a)
4606
4621
  if(t)return a.info("Auto-resolved parent session",{parentSessionId:t}),t
4607
4622
  a.info("No parent session; filing report as broadcast",{sessionId:_})})()
4608
- a.info("Submitting report",{sessionId:_,parentSessionId:j,status:S})
4609
- const O=await d.createReport({fromSessionId:_,toSessionId:j,status:S,summary:h,details:p,...f?{relatesTo:f}:{},...w?{attention:w}:{},...$?{reportKind:$}:{},..."string"==typeof e.requestId&&e.requestId.trim()?{requestId:e.requestId.trim()}:"string"==typeof e.area&&e.area.trim()?{area:e.area.trim()}:{},...Array.isArray(e.ruleVerdicts)&&e.ruleVerdicts.length?{extraContent:{ruleVerdicts:e.ruleVerdicts}}:{}}),D=await n(_)??"agent",F=O.content,N="string"==typeof F?.requestId?F.requestId:"request"===F?.anchor?.type&&"string"==typeof F.anchor.id?F.anchor.id:void 0,z={alchemy:{kind:"worker-report",payload:{status:S,summary:h,details:p,fromAgent:D,fromSessionId:_,...f?{relatesTo:f}:{},...N&&/^req\d+$/.test(N)?{requestId:N}:{}}}},B=!(!e.toSessionId||"parent"===e.toSessionId),L=j??(await s(_,c,a).catch(()=>null)||void 0),H=L?await n(L):null
4623
+ a.info("Submitting report",{sessionId:_,parentSessionId:P,status:S})
4624
+ const O=await d.createReport({fromSessionId:_,toSessionId:P,status:S,summary:h,details:p,...f?{relatesTo:f}:{},...w?{attention:w}:{},...$?{reportKind:$}:{},..."string"==typeof e.requestId&&e.requestId.trim()?{requestId:e.requestId.trim()}:"string"==typeof e.area&&e.area.trim()?{area:e.area.trim()}:{},...Array.isArray(e.ruleVerdicts)&&e.ruleVerdicts.length?{extraContent:{ruleVerdicts:e.ruleVerdicts}}:{}}),D=await n(_)??"agent",F=O.content,N="string"==typeof F?.requestId?F.requestId:"request"===F?.anchor?.type&&"string"==typeof F.anchor.id?F.anchor.id:void 0,z={alchemy:{kind:"worker-report",payload:{status:S,summary:h,details:p,fromAgent:D,fromSessionId:_,...f?{relatesTo:f}:{},...N&&/^req\d+$/.test(N)?{requestId:N}:{}}}},B=!(!e.toSessionId||"parent"===e.toSessionId),L=P??(await s(_,c,a).catch(()=>null)||void 0),H=L?await n(L):null
4610
4625
  let U=!1
4611
4626
  try{const e=await C.sessionIdentity.getSessionRequestId(c,a,_),n=r.projectId
4612
4627
  if(e&&n){const r=await c.proxyGet(`/api/projects/${n}/requests/${e}`).catch(()=>null),o=(r?.data??r)?.type,{kindProfile:s}=await Promise.resolve().then(()=>t(87780))
@@ -4691,7 +4706,7 @@ const f=n.getSessionMessageClient()
4691
4706
  if(!f)throw new v.ValidationError("Session message client not available")
4692
4707
  if(!s){const e=o?.sessionId||C.sessionIdentity.getIdentity()?.sessionId
4693
4708
  if(!e)return r.warn("No session identity for list operation"),{content:[{type:"text",text:"\u26a0\ufe0f Could not determine current session ID. Unable to list messages without a session context."}]}
4694
- s=e,(0,j.logSessionIdentity)("session_message_operations.list","identity",{sessionId:s,fromCliOrigin:!!o?.sessionId})}const m=o?.sessionId||C.sessionIdentity.getIdentity()?.sessionId
4709
+ s=e,(0,P.logSessionIdentity)("session_message_operations.list","identity",{sessionId:s,fromCliOrigin:!!o?.sessionId})}const m=o?.sessionId||C.sessionIdentity.getIdentity()?.sessionId
4695
4710
  let g="string"==typeof e.requestId&&e.requestId?e.requestId:void 0
4696
4711
  if(!g&&m&&s&&s!==m)try{g=await C.sessionIdentity.getSessionRequestId(n,r,m)??void 0}catch{}r.debug("Listing messages",{sessionId:s,messageType:i,direction:a,status:c,readStatus:l,requestId:g})
4697
4712
  const y={sessionId:s,direction:a,limit:h,offset:p,...g?{requestId:g}:{}}
@@ -4710,7 +4725,7 @@ t.debug("Getting message",{messageCode:n})
4710
4725
  const s=await o.getMessage(n)
4711
4726
  return s?{content:[{type:"text",text:u(s)}]}:{content:[{type:"text",text:`\u274c Message with code ${n} not found.`}],isError:!0}}(e,A,h),"get-message")
4712
4727
  default:throw new v.ValidationError(`Unknown operation: ${O}. Valid operations: send, reply, list, get, offer-handoff, record-decision, brief`)}}catch(e){return A.error("Session message operation failed",{operation:O,error:(0,k.getErrorMessage)(e)}),{content:[{type:"text",text:`\u274c Error: ${(0,k.getErrorMessage)(e)}`}],isError:!0}}}
4713
- const y=t(87780),w=t(64545),b=t(70508),v=t(59860),k=t(58824),I=t(47617),$=t(82272),x=t(67904),S=t(22316),_=t(22746),E=t(4871),C=t(6688),q=t(69883),T=t(69048),R=t(34221),A=t(39844),P=t(43545),j=t(87280),O=t(29729),M=t(19670),D=t(53847),F=t(62032)
4728
+ const y=t(87780),w=t(64545),b=t(70508),v=t(59860),k=t(58824),I=t(47617),$=t(82272),x=t(67904),S=t(22316),_=t(22746),E=t(4871),C=t(6688),q=t(69883),T=t(69048),R=t(34221),A=t(39844),j=t(43545),P=t(87280),O=t(29729),M=t(19670),D=t(53847),F=t(62032)
4714
4729
  exports.zk="A worker asks you this while it builds. Answer from what the user said and what the record holds: reply with your answer (quote the user's words when they settle it). If the answer changes what the request asks, update its criteria first (request_operations update). If only the user can decide, reply with escalate: true and your recommended default in notes; the default must be safe to happen without them. When the question has no options, give the ways forward in questionContent.options."},22746(e,exports,t){exports.runSyncHold=async function(e){const{client:t,logger:n,messageCode:o,holdMs:s}=e,i=Date.now()+s,a=async e=>{try{await t.stampHoldOutcome(o,{holdDelivered:!0,clearHold:!0})}catch(e){n.warn("Hold claim failed; the arbiter may also inject this answer",{messageCode:o,error:(0,r.getErrorMessage)(e)})}return{kind:"answered",message:e}}
4715
4730
  let c=!1
4716
4731
  for(;Date.now()<i;){await new Promise(e=>setTimeout(e,3e3))
@@ -4848,21 +4863,21 @@ if(!r.ok)return null
4848
4863
  const n=await r.json()
4849
4864
  return n.success?n.data??null:null}catch{return null}}(l).catch(()=>null),E=(0,g.getServerUrl)(t,i),C=(async()=>{if(!a||!u)return null
4850
4865
  const e=a.getSessionRequestAssociationClient()
4851
- return e?await e.getSessionsForRequest(u,!0):null})().catch(e=>(i.debug("Failed to check for existing workers",{error:(0,v.getErrorMessage)(e)}),null)),[T,R,A,P]=await Promise.all([I,S,E,C])
4866
+ return e?await e.getSessionsForRequest(u,!0):null})().catch(e=>(i.debug("Failed to check for existing workers",{error:(0,v.getErrorMessage)(e)}),null)),[T,R,A,j]=await Promise.all([I,S,E,C])
4852
4867
  try{if(r(t,"Spawn agent type check",{callerSessionId:k||null,callerAgentType:T||null,pid:process.pid}),T){const e=(0,$.getAllowedSubagents)(T)
4853
- if(e&&!e.includes(l))return{content:[{type:"text",text:`\u274c Agent type '${T}' cannot spawn '${l}'.\n\n**Allowed subagents for ${T}:** ${e.join(", ")}\n\nUse one of the allowed agent types instead.`}],isError:!0}}}catch(e){r(t,"allowedSubagents check failed",{error:(0,v.getErrorMessage)(e)})}let j=R?.requestContextMode
4854
- if(!j){const e=(0,$.getBuiltInAgentConfig)(l)
4855
- j=e?.requestContextMode}if(j&&"none"!==j&&!u)return{content:[{type:"text",text:`\u274c Agent '${l}' requires a requestId to be provided.\n\nThis agent has requestContextMode: '${j}' which means it needs to work in the context of a specific request.\n\nPlease provide a requestId when spawning this agent.`}],isError:!0}
4856
- if(u&&"required"===j&&a)try{const e=await a.getRequestClient().getRequest(u)
4868
+ if(e&&!e.includes(l))return{content:[{type:"text",text:`\u274c Agent type '${T}' cannot spawn '${l}'.\n\n**Allowed subagents for ${T}:** ${e.join(", ")}\n\nUse one of the allowed agent types instead.`}],isError:!0}}}catch(e){r(t,"allowedSubagents check failed",{error:(0,v.getErrorMessage)(e)})}let P=R?.requestContextMode
4869
+ if(!P){const e=(0,$.getBuiltInAgentConfig)(l)
4870
+ P=e?.requestContextMode}if(P&&"none"!==P&&!u)return{content:[{type:"text",text:`\u274c Agent '${l}' requires a requestId to be provided.\n\nThis agent has requestContextMode: '${P}' which means it needs to work in the context of a specific request.\n\nPlease provide a requestId when spawning this agent.`}],isError:!0}
4871
+ if(u&&"required"===P&&a)try{const e=await a.getRequestClient().getRequest(u)
4857
4872
  if("draft"===e?.status){const t=e?.intake,r="rejected"===t?.status?`the intake reviewer rejected it: ${String(t?.objection||"").slice(0,240)||"(no objection text)"}`:"pending"===t?.status?"it is held at intake awaiting a verdict":"it has not been registered"
4858
4873
  return{content:[{type:"text",text:`\u274c ${u} is a DRAFT: ${r}.\n\nWork cannot start on drafts. Wait for the request to be registered (the user resolves the intake question from the timeline), or address the objection with a revised proposal. Do NOT spawn workers for draft requests.`}],isError:!0}}}catch(e){r(t,"draft-spawn guard read failed (continuing)",{error:(0,v.getErrorMessage)(e)})}if(r(t,"serverUrl resolved",{serverUrl:A}),!t.workspaceManager?.getCurrentContext(t.currentSessionId)?.basePath&&!t.basePath)throw new f.ValidationError("Working directory not available in context")
4859
4874
  const O=c?.sessionId
4860
4875
  let M=""
4861
- if(P){const e=(O?P.filter(e=>e.opencodeSessionId!==O):P).filter(e=>!1!==e.working)
4876
+ if(j){const e=(O?j.filter(e=>e.opencodeSessionId!==O):j).filter(e=>!1!==e.working)
4862
4877
  if(e.length>0){const t=e.map(e=>e.opencodeSessionId).join(", ")
4863
4878
  if(!h)return i.warn("Blocked spawn: request already has active workers",{requestId:u,existingWorkerCount:e.length,existingSessionIds:e.map(e=>e.opencodeSessionId)}),{content:[{type:"text",text:`\u274c Cannot spawn: Request ${u} already has ${e.length} active worker(s): ${t}\n\nOptions:\n\u2022 Use \`useExistingSession: "${e[0].opencodeSessionId}"\` to send work to the existing session\n\u2022 Use \`allowParallel: true\` if you really need multiple workers on the same request`}],isError:!0}
4864
4879
  M=`\u26a0\ufe0f Warning: Request ${u} already has ${e.length} active worker(s): ${t}. Proceeding anyway (allowParallel=true).\n\n`,i.warn("Spawning parallel subagent for request with existing active workers",{requestId:u,existingWorkerCount:e.length,existingSessionIds:e.map(e=>e.opencodeSessionId),allowParallel:!0})}}let D,F,N=d
4865
- u&&(D=`requests/${u}`,r(t,"Setting initialBranch for agent",{agent:l,requestId:u,initialBranch:D,agentRequestContextMode:j||"undefined"}),N="readonly"===j?`Working on request ${u} (READONLY mode - you cannot modify files, only explore and report).\n\n${d}`:`Working on request ${u}.\n\n${d}`)
4880
+ u&&(D=`requests/${u}`,r(t,"Setting initialBranch for agent",{agent:l,requestId:u,initialBranch:D,agentRequestContextMode:P||"undefined"}),N="readonly"===P?`Working on request ${u} (READONLY mode - you cannot modify files, only explore and report).\n\n${d}`:`Working on request ${u}.\n\n${d}`)
4866
4881
  let z,B=!1
4867
4882
  if(p){if(F=p,i.info("Using existing session for spawn",{sessionId:F,requestId:u}),!A)throw new f.ValidationError("Could not determine OpenCode server URL")
4868
4883
  try{let e
@@ -5498,7 +5513,7 @@ return`${e.ok?"ok ":"FAIL"} ${t}${e.ok?"":`: ${e.error||"no reason given"}`}${e
5498
5513
  try{if(i&&s?.projectId){const{resolveRequestIdOrError:e}=await Promise.resolve().then(()=>t(36651))
5499
5514
  let r
5500
5515
  try{const t=a?.sessionId||s?.currentSessionId,o=await e(i,n,t,"no active request")
5501
- o?.ok&&(r=o.requestId)}catch{}await i.getToolRecordClient().createToolRecord({type:"drive-site",projectId:s.projectId,...r?{requestId:r}:{},metadata:{url:o,finalUrl:f.finalUrl,title:f.title??null,steps:(f.steps||[]).length,failed:(f.steps||[]).filter(e=>!e.ok).length,consoleErrors:(f.consoleErrors||[]).length,shot:f.finalShot??null},note:`Drove ${f.finalUrl||o} (${(f.steps||[]).length} steps)`})}}catch(e){n.warn("drive_site: tool record failed (drive unaffected)",{error:e instanceof Error?e.message:String(e)})}c({success:!0})
5516
+ o?.ok&&(r=o.requestId)}catch{}await i.getToolRecordClient().createToolRecord({type:"drive-site",projectId:s.projectId,...r?{requestId:r}:{},metadata:{url:o,finalUrl:f.finalUrl,title:f.title??null,steps:(f.steps||[]).length,failed:(f.steps||[]).filter(e=>!e.ok).length,consoleErrors:(f.consoleErrors||[]).length,shot:f.finalShot??null,shots:[...(f.steps||[]).map(e=>e?.shot).filter(e=>"string"==typeof e),...f.finalShot?[f.finalShot]:[]]},note:`Drove ${f.finalUrl||o} (${(f.steps||[]).length} steps)`})}}catch(e){n.warn("drive_site: tool record failed (drive unaffected)",{error:e instanceof Error?e.message:String(e)})}c({success:!0})
5502
5517
  const y=/^data:(image\/[a-z+.-]+);base64,(.+)$/.exec(String(f.finalShotDataUrl||""))
5503
5518
  return{content:[...y?[{type:"image",data:y[2],mimeType:y[1]}]:[],{type:"text",text:g}]}}catch(e){return n.error("drive_site failed",{error:e}),c({success:!1,error:"exception"}),{content:[{type:"text",text:`drive_site failed: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}}
5504
5519
  const r=t(70901)},75010(e,exports,t){exports.handleFetchAsset=async function(e,t,i,a){const c=a.startTimer("tool_execution_time"),l=e=>(c({success:!1,error:"bad"}),{content:[{type:"text",text:e}],isError:!0})
@@ -5588,27 +5603,36 @@ var o=Object.getOwnPropertyDescriptor(t,r)
5588
5603
  o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,o)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),n=this&&this.__exportStar||function(e,exports){for(var t in e)"default"===t||Object.prototype.hasOwnProperty.call(exports,t)||r(exports,e,t)}
5589
5604
  Object.defineProperty(exports,"__esModule",{value:!0}),n(t(70441),exports),n(t(70270),exports)},70270(e,exports){Object.defineProperty(exports,"__esModule",{value:!0})},26540(e,exports){var t
5590
5605
  exports.LogLevel=void 0,function(e){e.ERROR="error",e.WARN="warn",e.INFO="info",e.DEBUG="debug"}(t||(exports.LogLevel=t={}))},76183(e,exports,t){function r(e){const t={...e._def,description:void 0}
5591
- if(e instanceof n.z.ZodObject){const n=Object.fromEntries(Object.entries(e.shape).map(([e,t])=>[e,r(t)]))
5592
- t.shape=()=>n}else e instanceof n.z.ZodOptional||e instanceof n.z.ZodNullable||e instanceof n.z.ZodDefault?t.innerType=r(t.innerType):e instanceof n.z.ZodArray?t.type=r(t.type):e instanceof n.z.ZodRecord&&(t.valueType=r(t.valueType))
5593
- return new e.constructor(t)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.ReplaceLinesSchema=exports.InsertLinesSchema=exports.PlannerOpsSchema=exports.ResearchFanoutSchema=exports.SubagentOperationsSchema=exports.TaskInspectSchema=exports.CompleteTaskSchema=exports.GetTaskInformationSchema=exports.GetRequestInformationSchema=exports.ListRequestsSchema=exports.ListTasksSchema=exports.SearchSchema=exports.QueryHistorySchema=exports.RequestDiffSchema=exports.MergePreviewSchema=exports.FileRecoverSchema=exports.FileHistorySchema=exports.DeleteFilesSchema=exports.DeleteFileSchema=exports.ReplaceInFilesSchema=exports.ReplaceStringsSchema=exports.ReplaceStringSchema=exports.MoveFilesSchema=exports.CreateDirectorySchema=exports.GetFileInfoSchema=exports.ListDirectorySchema=exports.ReadFilesSchema=exports.ViewAssetSchema=exports.WriteFileSchema=exports.UpdateTaskStatusSchema=exports.CreateTaskSchema=exports.CreateRequestSchema=exports.TargetConditionsSchema=exports.TargetConditionSchema=exports.CompleteRequestSchema=exports.BaselineSchema=exports.skipTestsSchema=exports.skipTestsReasonSchema=exports.ExecutedTestSchema=exports.TestVerificationSchema=exports.TestDefinitionSchema=exports.AcceptanceCriterionSchema=exports.RecordTypeEnum=exports.RequestStatusEnum=exports.TaskStatusEnum=exports.RequestStatusFilterEnum=exports.SettableRequestTypeEnum=exports.RequestTypeEnum=exports.TestCoverageTypeEnum=exports.CompletionStatusEnum=void 0,exports.EnvironmentUpdateSchema=exports.EnvironmentCreateSchema=exports.EnvironmentVerifyStackSchema=exports.EnvironmentStatusSchema=exports.EnvironmentTeardownSchema=exports.EnvironmentProvisionSchema=exports.EnvironmentGetSchema=exports.AskUserVisualSchema=exports.RequestVisualFeedbackSchema=exports.FetchAssetSchema=exports.PreviewSiteSchema=exports.CaptureSiteSchema=exports.DriveSiteSchema=exports.ReadSiteSchema=exports.ExperimentListSchema=exports.ExperimentStopSchema=exports.ExperimentStartSchema=exports.ResultInspectSchema=exports.ResultsSchema=exports.EnvironmentListSchema=exports.TestingProcessDeleteSchema=exports.TestingProcessCreateSchema=exports.TestingProcessGetSchema=exports.TestingProcessListSchema=exports.MetaOperationsSchema=exports.MetaAgentListSchema=exports.MetaWorkflowRemoveRecipeSchema=exports.MetaWorkflowAddRecipeSchema=exports.MetaHookCreateSchema=exports.MetaHookListSchema=exports.MetaRecipeRemoveHookSchema=exports.MetaRecipeAddHookSchema=exports.MetaRecipeCreateSchema=exports.MetaRecipeGetSchema=exports.MetaRecipeListSchema=exports.MetaWorkflowUpdateSchema=exports.MetaWorkflowCreateSchema=exports.MetaWorkflowGetSchema=exports.MetaWorkflowListSchema=exports.QuickReplaceSchema=exports.QuickWriteSchema=exports.RequestOperationsSchema=exports.ManageFilesSchema=exports.ModifyFileSchema=exports.RevertRequestSchema=exports.PlanWriteSchema=exports.PlanReadSchema=exports.DocumentOperationsSchema=exports.SearchDocumentsSchema=exports.CreateDocumentSchema=void 0,exports.AnswerQuestionSchema=exports.McpConnectionsSchema=exports.DirectiveOperationsSchema=exports.CommitToViewedSessionSchema=exports.SessionMessageOperationsSchema=exports.OpeningBriefSectionSchema=exports.ReportTestResultsSchema=exports.CommandsSchema=exports.RunSchema=exports.ExecuteTestCommandSchema=exports.TestsSchema=exports.TestingProcessUpdateSchema=exports.SetupFinishSchema=exports.EnvironmentSetupSchema=exports.EnvironmentVerifySchema=exports.EnvironmentDeleteSchema=void 0
5594
- const n=t(11569),o=t(8955),s=t(94466),i=e=>"string"!=typeof e||e.trim()?e:void 0,a=(e,t,r={})=>n.z.string().refine(t=>!(!r.allowEmpty||""!==t)||!!t&&e.some(e=>e.test(t)),{message:t}),c=a([s.TASK_REF_PATTERN,s.TASK_REF_SHORT_PATTERN],"Task ID must be req######+#NN (e.g. req000005#03) or a short form like #01, 01, or 1 (resolved against the active request)."),l=a([/^req\d{6}$/],"Request ID must match format: req###### (e.g. req000001)"),d=a([/^doc_[0-9A-Z]{26}$/i,/^(doc|plan|quest|jour)\d{6}$/],"Document ID must match format: doc_[26 alphanumeric] (ULID) or doc######/plan######/quest######/jour###### (local ID)",{allowEmpty:!0}),u=e=>e.path&&e.documentId?{...e,documentId:void 0}:e,h=e=>Boolean(e.path)||Boolean(e.documentId)
5595
- exports.CompletionStatusEnum=n.z.enum(["complete","incomplete","partial"]),exports.TestCoverageTypeEnum=n.z.enum(["unit","e2e","integration","manual"]),exports.RequestTypeEnum=n.z.enum(["code","quick-edit","drive","writing","engineering","setup"]),exports.SettableRequestTypeEnum=n.z.enum(["code","drive","writing","engineering"]),exports.RequestStatusFilterEnum=n.z.enum(["draft","open","in_progress","ready_for_review","completing","resolving_conflicts","conflicted","completed","canceled","reverted","in_flight"]).describe("A status, or in_flight: every request under way."),exports.TaskStatusEnum=n.z.enum(["pending","in_progress","ready_for_review","completed","canceled","reverted"]),exports.RequestStatusEnum=n.z.enum(["open","in_progress","ready_for_review","completing","completed","canceled","reverted","conflicted"]),exports.RecordTypeEnum=n.z.enum(["write","modify","blocker","resolution","discovery","test","delete"]),exports.AcceptanceCriterionSchema=n.z.object({description:n.z.string(),createdAt:n.z.string().optional(),updatedAt:n.z.string().optional()}),exports.TestDefinitionSchema=n.z.object({id:n.z.string(),description:n.z.string(),status:exports.CompletionStatusEnum,coverageType:exports.TestCoverageTypeEnum,accepts:n.z.array(n.z.string())}),exports.TestVerificationSchema=n.z.object({criteria:n.z.array(n.z.string()),tests:n.z.array(n.z.string()),coverageType:exports.TestCoverageTypeEnum,coverageRatio:n.z.number(),createdAt:n.z.string().optional(),updatedAt:n.z.string().optional()}),exports.ExecutedTestSchema=n.z.object({id:n.z.string(),testId:n.z.string(),status:exports.CompletionStatusEnum,results:n.z.string(),coverage:n.z.array(n.z.string()),executedAt:n.z.string()}),exports.skipTestsReasonSchema=n.z.string().min(20).optional().describe("Opt out of all tests (20+ characters); refused when any is blocking."),exports.skipTestsSchema=n.z.array(n.z.object({commandName:n.z.string().min(1),reason:n.z.string().min(20)})).optional().describe("Skip some advisory test commands, each with why (20+ characters)."),exports.BaselineSchema=n.z.object({metric:n.z.string().regex(/^[A-Za-z_][A-Za-z0-9_.-]{0,59}$/).describe('"time" (the command\'s running time, seconds) or the name of a number it prints ("items_per_s: 812").'),better:n.z.enum(["lower","higher"]),tolerancePct:n.z.number().min(0).max(1e3).optional().describe("Percent worse still counted as no worse; default 10, or the user's number."),atLeast:n.z.number().min(0).optional().describe("Minimum absolute worsening that counts (default 0.1 for time, else 0)."),repeats:n.z.number().int().min(1).max(9).optional().describe("Runs per side, default 3; 1 for a number that never varies."),measures:n.z.enum(["time","size","count","rate","other"]).optional().describe('"time" for any duration ("solver_ms=12"), "size", "count", "rate" (per second), else "other".')}).describe("Only when the user asks that a measured number must not get worse (a time, a test count, a size); needs `command`, kind objective. Measured side by side before and after in the project's box; a regression waits for the user's sign-off."),exports.CompleteRequestSchema=n.z.object({status:exports.RequestStatusEnum,acceptanceCriteria:n.z.array(exports.AcceptanceCriterionSchema),testVerification:exports.TestVerificationSchema.optional(),completionSummary:n.z.string().optional()}),exports.TargetConditionSchema=n.z.object({id:n.z.string().optional().describe("Kept on an edit."),words:n.z.string().min(1).max(200).describe("What must hold, in the user's words."),command:n.z.string().optional().describe("The saved command that prints it, by name (SAVED COMMANDS in your context); omit until one exists."),metric:n.z.string().optional().describe("The name before its number (`name: 1.9`); omit for a lone number."),min:n.z.number().optional().describe('The user\'s lower bound ("at least 3": 3 meets it), set even before a command exists.'),max:n.z.number().optional().describe('The user\'s upper bound ("under 55" or "at most 55": 55 meets it), set even before a command exists.'),unit:n.z.string().max(12).optional().describe('The unit the user stated for the number ("ms", "kB", "%"); omit when they stated none.')}),exports.TargetConditionsSchema=n.z.array(exports.TargetConditionSchema).max(8).nullable().describe("The thread's target: met when every condition holds on main, a bound counting its own number as met. [] or null clears it."),exports.CreateRequestSchema=n.z.object({title:n.z.string().optional(),process:n.z.string().optional().describe("The workflow process it follows, by name, when it clearly is that kind of work: sets the kind and adds its guidance as criteria."),userSaid:n.z.string().min(8).max(600).optional().describe("The phrase of the user's that asks for this, copied exactly (an excerpt is matched). Pass it whenever the request comes from what they wrote; required for a 'gate' criterion, whose words must ask for a lasting check."),type:exports.SettableRequestTypeEnum.describe("'code': builds or fixes behaviour. 'writing': prose in the repo (docs, page copy). 'drive': the driver exercises the product as its user would against the criteria as claims; no branch, no merge, an unmet claim waits for the user. 'engineering': a model, simulation or analysis whose numbers are the product, reviewed on assumptions and evidence; prefer it over 'code' when the deliverable is a result."),description:n.z.string().optional().describe('What to build or find out and why: the record, not a reply (guidance on how you talk to the user does not apply). Call the user "you".'),quotesMessage:n.z.boolean().optional().describe("true when the user's message is the specification: it is copied in word for word, and your description is only what you add. Do not write their message out yourself. userSaid picks which message."),acceptanceCriteria:n.z.array(n.z.union([n.z.string(),n.z.object({description:n.z.string().min(1),beforeMerge:n.z.boolean().optional().describe("[user-input] only: the user asked to check it before it merges; the merge then waits for them at every Autonomy."),command:n.z.string().min(1).max(500).optional().describe("The command that decides it, if one does, as it runs in the project's box (not in the text). Written before the work exists: check what the result does, not how it is worded."),environment:n.z.string().min(1).max(120).optional().describe("The registered environment that runs its command when the check's box cannot (a browser suite in a Playwright environment); an unknown or unfinished one is asked for or waited on."),kind:n.z.enum(["objective","subjective","gate"]).describe("objective: provable by running something (output, files, exit codes), even with no tests yet. subjective: needs judgment. gate: a check on every merge from now on, met by a test process registered for this request."),baseline:exports.BaselineSchema.optional()})])).optional().describe('Done-conditions other than the bars in `target`: a string, or { description, kind }; split a mixed claim. What must be true of the result, never that a check ran. What must come from the user is its own criterion marked [user-input] (the end card asks for it). Address the user as "you".'),draft:n.z.boolean().optional().describe("A draft: nothing runs until the user starts it (a title alone is fine). How a worker files work nobody asked for (follows: its request)."),delegate:n.z.boolean().optional(),follows:n.z.string({required_error:"Required. Every request either follows earlier work or starts fresh: pass the origin request id (req######) or the word 'new'."}).refine(e=>"new"===e||/^(round:|new:)?req\d{6}$/.test(e),{message:"Pass a request id like req000031, 'round:req000031' for another round of work that has landed, 'new:req000031' for new work that grew out of it, or 'new' for genuinely new work."}).describe("The only link between requests. 'round:req######': another pass at what that completed request built (bigger, the wording back), shown as one item; pass only follows and type, it keeps the request's title and criteria and takes the user's message as its change. 'req######': a follow-up or fix of it, only when the user pointed at it or you are working it. 'new': fresh work, anything asked on its own, even touching earlier work; 'new:req######' when it grew out of that one (own thread and budget). Never the project's founding request."),planDocumentId:n.z.string().optional().describe("The plan that decomposes this work (plan######)."),scheduleDocumentId:n.z.string().optional().describe("Only when a schedule told you to create it: the id it gave."),questDocumentId:n.z.string().optional(),waitsOn:n.z.array(n.z.string().regex(/^req\d{6}$/)).max(5).optional().describe("Requests it waits for: it starts once all have landed (a canceled one never does: move or clear the wait). Declare it here; work is dispatched at registration. Growing out of an unlanded request: this or startsNow."),waitReason:n.z.string().optional().describe("With waitsOn (required): what it needs from the one it waits for, as the user reads it. Needing nothing means no wait."),startsNow:n.z.boolean().optional().describe("The other answer to waitsOn: start now beside the unlanded request. The user's words decide; silent on order, wait only when it builds on what that one adds."),asked:n.z.array(n.z.string().regex(/^Q-[A-Z0-9]+-\d+$/)).max(5).optional().describe("Your open questions (Q-codes) whose answer this builds on; the worker gets the answer and does not re-ask."),userChoices:n.z.array(n.z.string().regex(/^Q-[A-Za-z0-9]+-\d+$/)).max(10).optional().describe("Cards the user answered (or still may) that this builds on; their picks count as sources in review, so carry the picked words into the description. Cards closed by an agent, default or withdrawal are refused."),replaces:n.z.string().regex(/^req\d{6}$/).optional().describe("The canceled request this refiles; its waiters move here."),areas:n.z.array(n.z.string()).max(3).optional().describe("1-3 work areas, required unless draft: lowercase kebab paths ('graphics/opengl'). Pick from the project's areas (WORK AREAS when your context lists them, else list-areas); a new name only when nothing fits, under an existing parent."),budget:n.z.number().positive().max(1e5).optional().describe('A budget the user named ("up to $3"), dollars at list price, their words in userSaid: the thread\'s; at it, nothing new starts until they allow more.'),target:n.z.array(exports.TargetConditionSchema,{required_error:'Required. The bars the user set on a number, each { words, max or min } ("under 200 kB": max 200); [] when they set none.'}).max(8).describe('Every bar the user set on a number ("under 200 kB": max 200), in their words; [] when they set none. Each is shown as a criterion with its reading and is the thread\'s target, read on main: write no other criterion for it.'),estimate:n.z.number().positive().max(1e5).optional().describe("Expected cost in dollars at list price, judged from recent requests.")}),exports.CreateTaskSchema=n.z.object({requestId:l,title:n.z.string(),description:n.z.string()}),exports.UpdateTaskStatusSchema=n.z.object({taskId:c,status:exports.TaskStatusEnum,note:n.z.string()}),exports.WriteFileSchema=n.z.object({path:n.z.string().optional(),documentId:d.optional(),content:n.z.union([n.z.string(),n.z.array(n.z.string())]).optional(),fromResult:n.z.string().optional().describe('Instead of content: a recorded result (its address, or a unique prefix) whose bytes become this file, unchanged. For a file made somewhere you cannot write the worktree from, e.g. a .docx made in a sealed box and recorded with results({ operation: "record", box }). Files only (with path), up to 20 MB; bulk stays in the store (results pin).'),format:n.z.enum(["text","json"]).optional(),append:n.z.boolean().optional(),comment:n.z.string()}).transform(u).refine(h,{message:"path or documentId required"}).refine(e=>void 0!==e.content!==Boolean(e.fromResult),{message:"pass content or fromResult (exactly one)"}),exports.ViewAssetSchema=n.z.object({filename:n.z.string().optional().describe("An image in .alchemy_lab/assets/, as an asset:<filename> ref names it."),path:n.z.string().optional().describe("An image, PDF or office file (Word, Excel, PowerPoint, OpenDocument, .doc/.xls/.ppt/.rtf) in the working tree."),result:n.z.string().optional().describe("A recorded result: its address or a unique prefix."),pages:n.z.string().optional().describe('e.g. "3", "12-18" or "1,4,7-9"; at most 20 per view, required for documents over 20 pages.'),revision:n.z.string().optional().describe('With path: the file as committed at this commit, branch or tag; "base" is the version before this branch changed it.')}),exports.ReadFilesSchema=n.z.object({paths:n.z.array(n.z.object({path:n.z.string().optional(),documentId:d.optional(),lines:n.z.string().optional(),symbol:n.z.string().max(200).optional()}).transform(u).refine(h,{message:"path or documentId required"})),encoding:n.z.enum(["utf8","utf-8","ascii","binary"]).optional()}),exports.ListDirectorySchema=n.z.object({path:n.z.string(),levels:n.z.number().min(1).max(4).optional(),sortBy:n.z.enum(["name","modified","size","type"]).optional()}),exports.GetFileInfoSchema=n.z.object({path:n.z.string()}),exports.CreateDirectorySchema=n.z.object({path:n.z.string(),comment:n.z.string().optional()}),exports.MoveFilesSchema=n.z.object({operations:n.z.array(n.z.object({source:n.z.string(),destination:n.z.string()})),comment:n.z.string()}),exports.ReplaceStringSchema=n.z.object({path:n.z.string(),replacements:n.z.array(n.z.object({old_str:n.z.string(),new_str:n.z.string()})),mode:n.z.enum(["unique","all"]).optional(),comment:n.z.string()}),exports.ReplaceStringsSchema=n.z.object({operations:n.z.array(n.z.object({path:n.z.string().optional(),documentId:d.optional(),replacements:n.z.array(n.z.object({old_str:n.z.string(),new_str:n.z.string()})),mode:n.z.enum(["unique","all"]).optional()}).transform(u).refine(h,{message:"path or documentId required"})),comment:n.z.string()}),exports.ReplaceInFilesSchema=n.z.object({operations:n.z.array(n.z.object({path:n.z.string().optional(),documentId:d.optional(),replacements:n.z.array(n.z.object({old_str:n.z.string().min(1,"old_str cannot be empty"),new_str:n.z.string(),match_mode:n.z.enum(["unique","all"]).optional()})).min(1,"At least one replacement required"),fuzzy_match:n.z.boolean().optional()}).transform(u).refine(h,{message:"path or documentId required"})).min(1,"At least one operation required"),fuzzy_match:n.z.boolean().optional().default(!0),comment:n.z.string()}),exports.DeleteFileSchema=n.z.object({path:n.z.string(),comment:n.z.string()}),exports.DeleteFilesSchema=n.z.object({paths:n.z.array(n.z.string()).optional(),operations:n.z.array(n.z.object({path:n.z.string().optional(),documentId:d.optional()}).transform(u).refine(h,{message:"path or documentId required"})).optional(),comment:n.z.string()}).refine(e=>e.paths&&!e.operations||!e.paths&&e.operations,{message:"paths or operations required"}).refine(e=>e.paths?.length||e.operations?.length,{message:"path/operation required"}),exports.FileHistorySchema=n.z.object({path:n.z.string(),limit:n.z.number().min(1).max(100).default(10),showDiff:n.z.boolean().default(!1),showTraceability:n.z.boolean().default(!0),branch:n.z.string().optional(),commit:n.z.string().optional(),since:n.z.string().optional()}),exports.FileRecoverSchema=n.z.object({path:n.z.string(),commitHash:n.z.string(),createBackup:n.z.boolean().default(!0)}),exports.MergePreviewSchema=n.z.object({requestId:l,format:n.z.enum(["summary","unified"]).default("summary").describe("summary = per-file counts; unified = the diff the merge would add to your branch"),path:n.z.string().optional().describe('Optional git pathspec to scope the preview (e.g. "src/hud.css", "src/", "**/*.ts")')}),exports.RequestDiffSchema=n.z.object({requestId:l,format:n.z.enum(["summary","unified"]).default("summary"),path:n.z.string().optional()}),exports.QueryHistorySchema=n.z.object({queryType:n.z.enum(["file-history","task-file-history","request-file-history","recover","blame"],{errorMap:()=>({message:"Invalid queryType. Valid options: file-history, task-file-history, request-file-history, recover, blame"})}),fileHistory:n.z.object({path:n.z.string(),limit:n.z.number().min(1).max(100).default(10),showDiff:n.z.boolean().default(!1),showTraceability:n.z.boolean().default(!0),branch:n.z.string().optional(),commit:n.z.string().optional(),since:n.z.string().optional()}).optional(),taskHistory:n.z.object({taskId:c,showDiff:n.z.boolean().optional()}).optional(),requestHistory:n.z.object({requestId:l,detailLevel:n.z.enum(["summary","detailed"]).default("summary"),taskId:c.optional(),showDiff:n.z.boolean().optional(),fileFilter:n.z.string().optional()}).optional(),recover:n.z.object({path:n.z.string(),commitHash:n.z.string().optional(),createBackup:n.z.boolean().default(!0)}).optional(),blame:n.z.object({path:n.z.string(),lines:n.z.string().optional(),branch:n.z.string().optional()}).optional()}).refine(e=>"file-history"===e.queryType?e.fileHistory&&!e.requestHistory&&!e.recover:"task-file-history"===e.queryType?e.taskHistory&&!e.fileHistory&&!e.requestHistory&&!e.recover:"request-file-history"===e.queryType?e.requestHistory&&!e.fileHistory&&!e.recover:"recover"===e.queryType?e.recover&&!e.fileHistory&&!e.requestHistory&&!e.blame:"blame"===e.queryType&&e.blame&&!e.fileHistory&&!e.requestHistory&&!e.recover,{message:"Invalid query data"}),exports.SearchSchema=n.z.object({needle:n.z.string().optional(),directory:n.z.string().optional(),directories:n.z.array(n.z.string()).max(8).optional(),options:n.z.object({caseSensitive:n.z.boolean().optional(),fileExtension:n.z.string().optional(),maxResults:n.z.number().optional(),useRegex:n.z.boolean().optional(),searchIn:n.z.enum(["content","filename","both"]).default("content").optional(),contextLines:n.z.number().min(0).optional(),levels:n.z.number().min(1).max(4).optional(),sortBy:n.z.enum(["name","modified","size","type"]).optional()}).optional()}),exports.ListTasksSchema=n.z.object({requestId:l,filters:n.z.object({status:n.z.enum(["pending","in_progress","ready_for_review","completed","canceled","reverted"]).optional(),limit:n.z.number().min(1).max(100).default(20),offset:n.z.number().min(0).default(0),sortBy:n.z.enum(["created","updated"]).default("updated"),sortDirection:n.z.enum(["asc","desc"]).default("desc")}).optional()}),exports.ListRequestsSchema=n.z.object({filters:n.z.object({type:exports.RequestTypeEnum.optional(),status:exports.RequestStatusFilterEnum.optional(),planDocumentId:n.z.string().optional(),scheduleDocumentId:n.z.string().optional().describe("Requests a schedule fired: that schedule document."),questDocumentId:n.z.string().optional().describe("Legacy name of scheduleDocumentId."),dateFrom:n.z.string().optional().describe("Only requests with activity from this date on (YYYY-MM-DD means that whole day in the user's clock, or an ISO timestamp)."),dateTo:n.z.string().optional().describe("Only requests with activity up to this date (YYYY-MM-DD includes the whole day)."),limit:n.z.number().min(1).max(100).default(20),offset:n.z.number().min(0).default(0),sortBy:n.z.enum(["created","updated"]).default("updated"),sortDirection:n.z.enum(["asc","desc"]).default("desc")}).optional()}),exports.GetRequestInformationSchema=n.z.object({requestId:l}),exports.GetTaskInformationSchema=n.z.object({taskId:c}),exports.CompleteTaskSchema=n.z.object({taskId:c,summary:n.z.string()}),exports.TaskInspectSchema=n.z.object({operation:n.z.enum(["get-info","list"]),taskId:c.optional(),requestId:l.optional(),status:n.z.enum(["pending","in_progress","ready_for_review","completed","canceled","reverted"]).optional(),limit:n.z.number().min(1).max(100).default(20),offset:n.z.number().min(0).default(0),sortBy:n.z.enum(["created","updated"]).default("updated"),sortDirection:n.z.enum(["asc","desc"]).default("desc")}).superRefine((e,t)=>{"get-info"!==e.operation||e.taskId||t.addIssue({code:"custom",message:'taskId is required for get-info. Example: { "operation": "get-info", "taskId": "req000001#01" }'}),"list"!==e.operation||e.requestId||t.addIssue({code:"custom",message:'requestId is required for list. Example: { "operation": "list", "requestId": "req000001" }'})})
5596
- const p=n.z.string().min(1).describe("OpenCode session ID")
5597
- exports.SubagentOperationsSchema=n.z.object({sessionId:p.optional(),operation:n.z.enum(["spawn","continue","check-status","abort","read-messages","list-sessions"]),prompt:n.z.string().min(1).describe("Instructions for the subagent (required for spawn and continue)").optional(),agent:n.z.string().default("work").refine(e=>(0,o.isValidAgent)(e),{message:"Invalid agent. Check tool description for available agents."}).describe("The subagent type to spawn (see tool description for available agents)").optional(),description:n.z.string().max(60).describe("Brief label for the UI (max 60 chars, spawn only)").optional(),requestId:n.z.string().describe("Request ID: associates work (spawn) or filters results (list-sessions)").optional(),allowParallel:n.z.boolean().describe("Allow spawning even if request already has active workers (spawn only)").optional(),useExistingSession:n.z.string().describe("Existing session ID to send prompt to instead of creating new session (spawn only)").optional(),limit:n.z.number().min(1).max(100).describe("Max items to return (read-messages: max 50, list-sessions: max 100)").optional(),compact:n.z.boolean().describe("read-messages: return a one-line index of EACH message with tool-call markers (the subagent`s trajectory at a glance: which tools ran, in what order, which failed), instead of full text. Use to see what a subagent actually DID, then `select` one for detail.").optional(),select:n.z.number().min(1).describe("read-messages: return ONLY this message number (from the compact list) in full structured detail: each tool call as {tool, input, status, output}, plus its text. The objective record of one step.").optional(),activeOnly:n.z.boolean().describe("Only show sessions that are currently active/busy (list-sessions only)").optional(),minTokens:n.z.number().min(0).describe("Only show sessions with at least this many tokens (list-sessions only)").optional(),maxTokens:n.z.number().min(0).describe("Only show sessions with at most this many tokens (list-sessions only)").optional(),maxAgeHours:n.z.number().min(0).describe("Only show sessions newer than X hours (list-sessions only)").optional()}).refine(e=>"spawn"===e.operation?!!e.prompt:"continue"===e.operation?!!e.prompt&&!!e.sessionId:"check-status"===e.operation||"abort"===e.operation||"read-messages"===e.operation?!!e.sessionId:"list-sessions"===e.operation,{message:"spawn requires prompt; continue requires prompt+sessionId; check-status/abort/read-messages require sessionId"}),exports.ResearchFanoutSchema=n.z.object({goal:n.z.string().min(1).optional().describe("What to research; passed to every angle. Required to START a run."),angles:n.z.array(n.z.string()).optional().describe("Research angles to fan out over. Omit to use the default set (data-model, call-sites, prior-art/history, external/web, test-surface)."),planId:n.z.string().optional().describe("Plan document to reference the research report from when the run completes."),checkRunId:n.z.string().optional().describe("Pass a runId from a previous start to CHECK that run live progress instead of starting a new one.")}).refine(e=>!(!e.goal||!e.goal.trim())||!!e.checkRunId,{message:"Provide goal to start a run, or checkRunId to check one."}),exports.PlannerOpsSchema=n.z.object({operation:n.z.enum(["request","check-status","list","end"]),sessionId:p.optional(),prompt:n.z.string().min(1).describe("request (required): what to plan").optional(),description:n.z.string().max(60).describe("request: a short label").optional(),userRequested:n.z.boolean().describe("request: true only when the user asked for this plan themselves").optional(),userStarts:n.z.boolean().describe("request: the user said they will start the plan themselves").optional(),documentId:n.z.string().describe("request: an existing plan to evolve in place; end: the plan whose planner to end").optional(),activeOnly:n.z.boolean().optional(),limit:n.z.number().min(1).max(100).optional()}).refine(e=>"request"===e.operation?!!e.prompt:"check-status"===e.operation?!!e.sessionId:"list"===e.operation||"end"===e.operation&&(!!e.sessionId||!!e.documentId),{message:"request requires prompt; check-status requires sessionId; end requires sessionId or documentId"}),exports.InsertLinesSchema=n.z.object({operations:n.z.array(n.z.object({path:n.z.string().optional(),documentId:d.optional(),insertions:n.z.array(n.z.object({type:n.z.enum(["before","after","between"]),line:n.z.number().optional(),afterLine:n.z.number().optional(),beforeLine:n.z.number().optional(),content:n.z.union([n.z.string(),n.z.array(n.z.string())])}).refine(e=>"between"===e.type?void 0!==e.afterLine&&void 0!==e.beforeLine&&void 0===e.line:void 0!==e.line&&void 0===e.afterLine&&void 0===e.beforeLine,{message:"Invalid line parameters"}))}).transform(u).refine(h,{message:"path or documentId required"})),comment:n.z.string()}),exports.ReplaceLinesSchema=n.z.object({operations:n.z.array(n.z.object({path:n.z.string().optional(),documentId:d.optional(),replacements:n.z.array(n.z.object({lines:n.z.string(),content:n.z.union([n.z.string(),n.z.array(n.z.string())])}))}).transform(u).refine(h,{message:"path or documentId required"})),comment:n.z.string()}),exports.CreateDocumentSchema=n.z.object({requestId:l.optional(),filename:n.z.string().refine(e=>/\.(md|html?)$/i.test(e),{message:"Filename must end in .md (prose) or .html (a rendered page)"}),content:n.z.string(),comment:n.z.string(),scheduleIntervalSeconds:n.z.number().int().min(300).describe("Fire interval in seconds (min 300). Setting this makes the document a SCHEDULE: the runner periodically asks the alchemist to read it and create one linked request. 86400 = daily. Prefer scheduleAtTimes when the goal wants a time of day.").optional(),scheduleAtTimes:n.z.string().describe("Local time(s) of day to fire, e.g. '09:00' or '09:00,17:00'. Setting this makes the document a SCHEDULE that runs at that clock time instead of on an interval, and it starts at the next such time (never the moment it is created).").optional(),scheduleOnDays:n.z.string().describe("Which days scheduleAtTimes applies to: 'weekdays', 'weekends', or names like 'mon,thu'. Omit for every day.").optional(),schedulePrompt:n.z.string().describe('What each firing should do -- the instruction the alchemist receives per tick (e.g. "validate quotes.ndjson and file a short report; flag the user only on real breakage").').optional(),scheduleMaxPerDay:n.z.number().int().min(1).describe("Cap on requests it files per day (structural guard); only when the user named one. A goal with a target keeps reading it past the cap.").optional(),scheduleMaxInFlight:n.z.number().int().min(1).describe("Cap on live linked requests before firings pause (structural guard). Default 1.").optional(),target:exports.TargetConditionsSchema.optional(),scheduleBudgetUsd:n.z.number().positive().max(1e5).optional(),userSaid:n.z.string().max(600).optional()}),exports.SearchDocumentsSchema=n.z.object({query:n.z.string(),requestId:l.optional(),includeArchived:n.z.boolean().default(!1),maxResults:n.z.number().min(1).max(100).default(20),dateFrom:n.z.string().optional(),dateTo:n.z.string().optional(),searchIn:n.z.enum(["content","filename","both"]).default("both")}),exports.DocumentOperationsSchema=n.z.object({operation:n.z.enum(["create","update","search","create-snapshot","get-history","get-version","restore-version","archive","unarchive","list-annotations","create-annotation","reply-to-annotation","resolve-annotation","create-artifact-annotation","propose-standard"]),standardRules:n.z.array(n.z.object({text:n.z.string().min(1).max(600),section:n.z.string().min(1).max(120),checked:n.z.boolean(),kinds:n.z.array(n.z.enum(["code","engineering","writing","drive"])).max(4).optional()})).min(1).max(12).optional(),documentId:d.optional(),requestId:l.optional(),filename:n.z.string().optional(),content:n.z.string().optional(),comment:n.z.string().optional(),scheduleIntervalSeconds:n.z.number().int().min(300).optional(),scheduleAtTimes:n.z.string().optional(),scheduleOnDays:n.z.string().optional(),schedulePrompt:n.z.string().optional(),scheduleMaxPerDay:n.z.number().int().min(1).optional(),scheduleMaxInFlight:n.z.number().int().min(1).optional(),target:exports.TargetConditionsSchema.optional(),scheduleEnabled:n.z.boolean().optional().describe("update: false pauses, true resumes (with scheduleReason); archive only a finished goal."),scheduleBudgetUsd:n.z.number().positive().max(1e5).nullable().optional().describe("Dollars at list price for the whole goal (its requests and your turns on it); at it, the goal stops until the user allows more. null removes it."),userSaid:n.z.string().min(8).max(600).optional().describe("With scheduleBudgetUsd or target: the user's words, exact."),scheduleReason:n.z.string().optional().describe("Why paused or resumed; the user reads it."),query:n.z.string().optional(),includeArchived:n.z.boolean().default(!1),maxResults:n.z.number().min(1).max(100).default(20),dateFrom:n.z.string().optional(),dateTo:n.z.string().optional(),searchIn:n.z.enum(["content","filename","both"]).default("both"),replacements:n.z.array(n.z.object({old_str:n.z.string(),new_str:n.z.string()})).optional(),mode:n.z.enum(["unique","all"]).optional(),versionLabel:n.z.string().optional(),changeSummary:n.z.string().optional(),versionNumber:n.z.number().int().min(1).optional(),selectedText:n.z.string().optional(),prefixContext:n.z.string().optional(),suffixContext:n.z.string().optional(),lineHint:n.z.number().int().optional(),body:n.z.string().optional(),annotationId:n.z.string().optional(),ref:n.z.string().optional(),file:n.z.string().optional(),line:n.z.union([n.z.number().int(),n.z.string()]).optional()}).superRefine((e,t)=>{const r=e.operation
5606
+ if(e instanceof o.z.ZodObject){const n=Object.fromEntries(Object.entries(e.shape).map(([e,t])=>[e,r(t)]))
5607
+ t.shape=()=>n}else e instanceof o.z.ZodOptional||e instanceof o.z.ZodNullable||e instanceof o.z.ZodDefault?t.innerType=r(t.innerType):e instanceof o.z.ZodArray?t.type=r(t.type):e instanceof o.z.ZodRecord&&(t.valueType=r(t.valueType))
5608
+ return new e.constructor(t)}function n(e){switch(e.operation){case"send":return e.type?null:'send needs "type": use "report" for a summary, a verdict or an update, or "question" to ask someone.'
5609
+ case"note":return"string"==typeof e.text&&e.text.trim()?null:'note needs "text": the note itself.'
5610
+ case"reply":return e.messageCode?null:'reply needs "messageCode": the code of the message you answer.'
5611
+ case"get":return e.messageCode?null:'get needs "messageCode": the code of the message to read.'
5612
+ case"withdraw":return e.messageCode?null:'withdraw needs "messageCode": the code of the message to withdraw.'
5613
+ case"record-decision":return e.decision?null:'record-decision needs "decision".'
5614
+ case"brief":return e.requestId&&Array.isArray(e.sections)&&e.sections.length>0?null:'brief needs "requestId" and a non-empty "sections" array.'
5615
+ case"list":case"offer-handoff":return null
5616
+ default:return'"operation" must be one of: send, note, reply, list, get, withdraw, record-decision, brief, offer-handoff.'}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.ReplaceLinesSchema=exports.InsertLinesSchema=exports.PlannerOpsSchema=exports.ResearchFanoutSchema=exports.SubagentOperationsSchema=exports.TaskInspectSchema=exports.CompleteTaskSchema=exports.GetTaskInformationSchema=exports.GetRequestInformationSchema=exports.ListRequestsSchema=exports.ListTasksSchema=exports.SearchSchema=exports.QueryHistorySchema=exports.RequestDiffSchema=exports.MergePreviewSchema=exports.FileRecoverSchema=exports.FileHistorySchema=exports.DeleteFilesSchema=exports.DeleteFileSchema=exports.ReplaceInFilesSchema=exports.ReplaceStringsSchema=exports.ReplaceStringSchema=exports.MoveFilesSchema=exports.CreateDirectorySchema=exports.GetFileInfoSchema=exports.ListDirectorySchema=exports.ReadFilesSchema=exports.ViewAssetSchema=exports.WriteFileSchema=exports.UpdateTaskStatusSchema=exports.CreateTaskSchema=exports.CreateRequestSchema=exports.TargetConditionsSchema=exports.TargetConditionSchema=exports.CompleteRequestSchema=exports.BaselineSchema=exports.skipTestsSchema=exports.skipTestsReasonSchema=exports.ExecutedTestSchema=exports.TestVerificationSchema=exports.TestDefinitionSchema=exports.AcceptanceCriterionSchema=exports.RecordTypeEnum=exports.RequestStatusEnum=exports.TaskStatusEnum=exports.RequestStatusFilterEnum=exports.SettableRequestTypeEnum=exports.RequestTypeEnum=exports.TestCoverageTypeEnum=exports.CompletionStatusEnum=void 0,exports.EnvironmentUpdateSchema=exports.EnvironmentCreateSchema=exports.EnvironmentVerifyStackSchema=exports.EnvironmentStatusSchema=exports.EnvironmentTeardownSchema=exports.EnvironmentProvisionSchema=exports.EnvironmentGetSchema=exports.AskUserVisualSchema=exports.RequestVisualFeedbackSchema=exports.FetchAssetSchema=exports.PreviewSiteSchema=exports.CaptureSiteSchema=exports.DriveSiteSchema=exports.ReadSiteSchema=exports.ExperimentListSchema=exports.ExperimentStopSchema=exports.ExperimentStartSchema=exports.ResultInspectSchema=exports.ResultsSchema=exports.EnvironmentListSchema=exports.TestingProcessDeleteSchema=exports.TestingProcessCreateSchema=exports.TestingProcessGetSchema=exports.TestingProcessListSchema=exports.MetaOperationsSchema=exports.MetaAgentListSchema=exports.MetaWorkflowRemoveRecipeSchema=exports.MetaWorkflowAddRecipeSchema=exports.MetaHookCreateSchema=exports.MetaHookListSchema=exports.MetaRecipeRemoveHookSchema=exports.MetaRecipeAddHookSchema=exports.MetaRecipeCreateSchema=exports.MetaRecipeGetSchema=exports.MetaRecipeListSchema=exports.MetaWorkflowUpdateSchema=exports.MetaWorkflowCreateSchema=exports.MetaWorkflowGetSchema=exports.MetaWorkflowListSchema=exports.QuickReplaceSchema=exports.QuickWriteSchema=exports.RequestOperationsSchema=exports.ManageFilesSchema=exports.ModifyFileSchema=exports.RevertRequestSchema=exports.PlanWriteSchema=exports.PlanReadSchema=exports.DocumentOperationsSchema=exports.SearchDocumentsSchema=exports.CreateDocumentSchema=void 0,exports.AnswerQuestionSchema=exports.McpConnectionsSchema=exports.DirectiveOperationsSchema=exports.CommitToViewedSessionSchema=exports.SessionMessageOperationsSchema=exports.OpeningBriefSectionSchema=exports.ReportTestResultsSchema=exports.CommandsSchema=exports.RunSchema=exports.ExecuteTestCommandSchema=exports.TestsSchema=exports.TestingProcessUpdateSchema=exports.SetupFinishSchema=exports.EnvironmentSetupSchema=exports.EnvironmentVerifySchema=exports.EnvironmentDeleteSchema=void 0,exports.sessionMessageMissing=n
5617
+ const o=t(11569),s=t(8955),i=t(94466),a=e=>"string"!=typeof e||e.trim()?e:void 0,c=(e,t,r={})=>o.z.string().refine(t=>!(!r.allowEmpty||""!==t)||!!t&&e.some(e=>e.test(t)),{message:t}),l=c([i.TASK_REF_PATTERN,i.TASK_REF_SHORT_PATTERN],"Task ID must be req######+#NN (e.g. req000005#03) or a short form like #01, 01, or 1 (resolved against the active request)."),d=c([/^req\d{6}$/],"Request ID must match format: req###### (e.g. req000001)"),u=c([/^doc_[0-9A-Z]{26}$/i,/^(doc|plan|quest|jour)\d{6}$/],"Document ID must match format: doc_[26 alphanumeric] (ULID) or doc######/plan######/quest######/jour###### (local ID)",{allowEmpty:!0}),h=e=>e.path&&e.documentId?{...e,documentId:void 0}:e,p=e=>Boolean(e.path)||Boolean(e.documentId)
5618
+ exports.CompletionStatusEnum=o.z.enum(["complete","incomplete","partial"]),exports.TestCoverageTypeEnum=o.z.enum(["unit","e2e","integration","manual"]),exports.RequestTypeEnum=o.z.enum(["code","quick-edit","drive","writing","engineering","setup"]),exports.SettableRequestTypeEnum=o.z.enum(["code","drive","writing","engineering"]),exports.RequestStatusFilterEnum=o.z.enum(["draft","open","in_progress","ready_for_review","completing","resolving_conflicts","conflicted","completed","canceled","reverted","in_flight"]).describe("A status, or in_flight: every request under way."),exports.TaskStatusEnum=o.z.enum(["pending","in_progress","ready_for_review","completed","canceled","reverted"]),exports.RequestStatusEnum=o.z.enum(["open","in_progress","ready_for_review","completing","completed","canceled","reverted","conflicted"]),exports.RecordTypeEnum=o.z.enum(["write","modify","blocker","resolution","discovery","test","delete"]),exports.AcceptanceCriterionSchema=o.z.object({description:o.z.string(),createdAt:o.z.string().optional(),updatedAt:o.z.string().optional()}),exports.TestDefinitionSchema=o.z.object({id:o.z.string(),description:o.z.string(),status:exports.CompletionStatusEnum,coverageType:exports.TestCoverageTypeEnum,accepts:o.z.array(o.z.string())}),exports.TestVerificationSchema=o.z.object({criteria:o.z.array(o.z.string()),tests:o.z.array(o.z.string()),coverageType:exports.TestCoverageTypeEnum,coverageRatio:o.z.number(),createdAt:o.z.string().optional(),updatedAt:o.z.string().optional()}),exports.ExecutedTestSchema=o.z.object({id:o.z.string(),testId:o.z.string(),status:exports.CompletionStatusEnum,results:o.z.string(),coverage:o.z.array(o.z.string()),executedAt:o.z.string()}),exports.skipTestsReasonSchema=o.z.string().min(20).optional().describe("Opt out of all tests (20+ characters); refused when any is blocking."),exports.skipTestsSchema=o.z.array(o.z.object({commandName:o.z.string().min(1),reason:o.z.string().min(20)})).optional().describe("Skip some advisory test commands, each with why (20+ characters)."),exports.BaselineSchema=o.z.object({metric:o.z.string().regex(/^[A-Za-z_][A-Za-z0-9_.-]{0,59}$/).describe('"time" (the command\'s running time, seconds) or the name of a number it prints ("items_per_s: 812").'),better:o.z.enum(["lower","higher"]),tolerancePct:o.z.number().min(0).max(1e3).optional().describe("Percent worse still counted as no worse; default 10, or the user's number."),atLeast:o.z.number().min(0).optional().describe("Minimum absolute worsening that counts (default 0.1 for time, else 0)."),repeats:o.z.number().int().min(1).max(9).optional().describe("Runs per side, default 3; 1 for a number that never varies."),measures:o.z.enum(["time","size","count","rate","other"]).optional().describe('"time" for any duration ("solver_ms=12"), "size", "count", "rate" (per second), else "other".')}).describe("Only when the user asks that a measured number must not get worse (a time, a test count, a size); needs `command`, kind objective. Measured side by side before and after in the project's box; a regression waits for the user's sign-off."),exports.CompleteRequestSchema=o.z.object({status:exports.RequestStatusEnum,acceptanceCriteria:o.z.array(exports.AcceptanceCriterionSchema),testVerification:exports.TestVerificationSchema.optional(),completionSummary:o.z.string().optional()}),exports.TargetConditionSchema=o.z.object({id:o.z.string().optional().describe("Kept on an edit."),words:o.z.string().min(1).max(200).describe("What must hold, in the user's words."),command:o.z.string().optional().describe("The saved command that prints it, by name (SAVED COMMANDS in your context); omit until one exists."),metric:o.z.string().optional().describe("The name before its number (`name: 1.9`); omit for a lone number."),min:o.z.number().optional().describe('The user\'s lower bound ("at least 3": 3 meets it), set even before a command exists.'),max:o.z.number().optional().describe('The user\'s upper bound ("under 55" or "at most 55": 55 meets it), set even before a command exists.'),unit:o.z.string().max(12).optional().describe('The unit the user stated for the number ("ms", "kB", "%"); omit when they stated none.')}),exports.TargetConditionsSchema=o.z.array(exports.TargetConditionSchema).max(8).nullable().describe("The thread's target: met when every condition holds on main, a bound counting its own number as met. [] or null clears it."),exports.CreateRequestSchema=o.z.object({title:o.z.string().optional(),process:o.z.string().optional().describe("The workflow process it follows, by name, when it clearly is that kind of work: sets the kind and adds its guidance as criteria."),userSaid:o.z.string().min(8).max(600).optional().describe("The phrase of the user's that asks for this, copied exactly (an excerpt is matched). Pass it whenever the request comes from what they wrote; required for a 'gate' criterion, whose words must ask for a lasting check."),type:exports.SettableRequestTypeEnum.describe("'code': builds or fixes behaviour. 'writing': prose in the repo (docs, page copy). 'drive': the driver exercises the product as its user would against the criteria as claims; no branch, no merge, an unmet claim waits for the user. 'engineering': a model, simulation or analysis whose numbers are the product, reviewed on assumptions and evidence; prefer it over 'code' when the deliverable is a result."),description:o.z.string().optional().describe('What to build or find out and why: the record, not a reply (guidance on how you talk to the user does not apply). Call the user "you".'),quotesMessage:o.z.boolean().optional().describe("true when the user's message is the specification: it is copied in word for word, and your description is only what you add. Do not write their message out yourself. userSaid picks which message."),acceptanceCriteria:o.z.array(o.z.union([o.z.string(),o.z.object({description:o.z.string().min(1),beforeMerge:o.z.boolean().optional().describe("[user-input] only: the user asked to check it before it merges; the merge then waits for them at every Autonomy."),command:o.z.string().min(1).max(500).optional().describe("The command that decides it, if one does, as it runs in the project's box (not in the text). Written before the work exists: check what the result does, not how it is worded."),environment:o.z.string().min(1).max(120).optional().describe("The registered environment that runs its command when the check's box cannot (a browser suite in a Playwright environment); an unknown or unfinished one is asked for or waited on."),kind:o.z.enum(["objective","subjective","gate"]).describe("objective: provable by running something (output, files, exit codes), even with no tests yet. subjective: needs judgment. gate: a check on every merge from now on, met by a test process registered for this request."),baseline:exports.BaselineSchema.optional()})])).optional().describe('Done-conditions other than the bars in `target`: a string, or { description, kind }; split a mixed claim. What must be true of the result, never that a check ran. What must come from the user is its own criterion marked [user-input] (the end card asks for it). Address the user as "you".'),draft:o.z.boolean().optional().describe("A draft: nothing runs until the user starts it (a title alone is fine). How a worker files work nobody asked for (follows: its request)."),delegate:o.z.boolean().optional(),follows:o.z.string({required_error:"Required. Every request either follows earlier work or starts fresh: pass the origin request id (req######) or the word 'new'."}).refine(e=>"new"===e||/^(round:|new:)?req\d{6}$/.test(e),{message:"Pass a request id like req000031, 'round:req000031' for another round of work that has landed, 'new:req000031' for new work that grew out of it, or 'new' for genuinely new work."}).describe("The only link between requests. 'round:req######': another pass at what that completed request built (bigger, the wording back), shown as one item; pass only follows and type, it keeps the request's title and criteria and takes the user's message as its change. 'req######': a follow-up or fix of it, only when the user pointed at it or you are working it. 'new': fresh work, anything asked on its own, even touching earlier work; 'new:req######' when it grew out of that one (own thread and budget). Never the project's founding request."),planDocumentId:o.z.string().optional().describe("The plan that decomposes this work (plan######)."),scheduleDocumentId:o.z.string().optional().describe("Only when a schedule told you to create it: the id it gave."),questDocumentId:o.z.string().optional(),waitsOn:o.z.array(o.z.string().regex(/^req\d{6}$/)).max(5).optional().describe("Requests it waits for: it starts once all have landed (a canceled one never does: move or clear the wait). Declare it here; work is dispatched at registration. Growing out of an unlanded request: this or startsNow."),waitReason:o.z.string().optional().describe("With waitsOn (required): what it needs from the one it waits for, as the user reads it. Needing nothing means no wait."),startsNow:o.z.boolean().optional().describe("The other answer to waitsOn: start now beside the unlanded request. The user's words decide; silent on order, wait only when it builds on what that one adds."),asked:o.z.array(o.z.string().regex(/^Q-[A-Z0-9]+-\d+$/)).max(5).optional().describe("Your open questions (Q-codes) whose answer this builds on; the worker gets the answer and does not re-ask."),userChoices:o.z.array(o.z.string().regex(/^Q-[A-Za-z0-9]+-\d+$/)).max(10).optional().describe("Cards the user answered (or still may) that this builds on; their picks count as sources in review, so carry the picked words into the description. Cards closed by an agent, default or withdrawal are refused."),replaces:o.z.string().regex(/^req\d{6}$/).optional().describe("The canceled request this refiles; its waiters move here."),areas:o.z.array(o.z.string()).max(3).optional().describe("1-3 work areas, required unless draft: lowercase kebab paths ('graphics/opengl'). Pick from the project's areas (WORK AREAS when your context lists them, else list-areas); a new name only when nothing fits, under an existing parent."),budget:o.z.number().positive().max(1e5).optional().describe('A budget the user named ("up to $3"), dollars at list price, their words in userSaid: the thread\'s; at it, nothing new starts until they allow more.'),target:o.z.array(exports.TargetConditionSchema,{required_error:'Required. The bars the user set on a number, each { words, max or min } ("under 200 kB": max 200); [] when they set none.'}).max(8).describe('Every bar the user set on a number ("under 200 kB": max 200), in their words; [] when they set none. Each is shown as a criterion with its reading and is the thread\'s target, read on main: write no other criterion for it.'),estimate:o.z.number().positive().max(1e5).optional().describe("Expected cost in dollars at list price, judged from recent requests.")}),exports.CreateTaskSchema=o.z.object({requestId:d,title:o.z.string(),description:o.z.string()}),exports.UpdateTaskStatusSchema=o.z.object({taskId:l,status:exports.TaskStatusEnum,note:o.z.string()}),exports.WriteFileSchema=o.z.object({path:o.z.string().optional(),documentId:u.optional(),content:o.z.union([o.z.string(),o.z.array(o.z.string())]).optional(),fromResult:o.z.string().optional().describe('Instead of content: a recorded result (its address, or a unique prefix) whose bytes become this file, unchanged. For a file made somewhere you cannot write the worktree from, e.g. a .docx made in a sealed box and recorded with results({ operation: "record", box }). Files only (with path), up to 20 MB; bulk stays in the store (results pin).'),format:o.z.enum(["text","json"]).optional(),append:o.z.boolean().optional(),comment:o.z.string()}).transform(h).refine(p,{message:"path or documentId required"}).refine(e=>void 0!==e.content!==Boolean(e.fromResult),{message:"pass content or fromResult (exactly one)"}),exports.ViewAssetSchema=o.z.object({filename:o.z.string().optional().describe("An image in .alchemy_lab/assets/, as an asset:<filename> ref names it."),path:o.z.string().optional().describe("An image, PDF or office file (Word, Excel, PowerPoint, OpenDocument, .doc/.xls/.ppt/.rtf) in the working tree."),result:o.z.string().optional().describe("A recorded result: its address or a unique prefix."),pages:o.z.string().optional().describe('e.g. "3", "12-18" or "1,4,7-9"; at most 20 per view, required for documents over 20 pages.'),revision:o.z.string().optional().describe('With path: the file as committed at this commit, branch or tag; "base" is the version before this branch changed it.')}),exports.ReadFilesSchema=o.z.object({paths:o.z.array(o.z.object({path:o.z.string().optional(),documentId:u.optional(),lines:o.z.string().optional(),symbol:o.z.string().max(200).optional()}).transform(h).refine(p,{message:"path or documentId required"})),encoding:o.z.enum(["utf8","utf-8","ascii","binary"]).optional()}),exports.ListDirectorySchema=o.z.object({path:o.z.string(),levels:o.z.number().min(1).max(4).optional(),sortBy:o.z.enum(["name","modified","size","type"]).optional()}),exports.GetFileInfoSchema=o.z.object({path:o.z.string()}),exports.CreateDirectorySchema=o.z.object({path:o.z.string(),comment:o.z.string().optional()}),exports.MoveFilesSchema=o.z.object({operations:o.z.array(o.z.object({source:o.z.string(),destination:o.z.string()})),comment:o.z.string()}),exports.ReplaceStringSchema=o.z.object({path:o.z.string(),replacements:o.z.array(o.z.object({old_str:o.z.string(),new_str:o.z.string()})),mode:o.z.enum(["unique","all"]).optional(),comment:o.z.string()}),exports.ReplaceStringsSchema=o.z.object({operations:o.z.array(o.z.object({path:o.z.string().optional(),documentId:u.optional(),replacements:o.z.array(o.z.object({old_str:o.z.string(),new_str:o.z.string()})),mode:o.z.enum(["unique","all"]).optional()}).transform(h).refine(p,{message:"path or documentId required"})),comment:o.z.string()}),exports.ReplaceInFilesSchema=o.z.object({operations:o.z.array(o.z.object({path:o.z.string().optional(),documentId:u.optional(),replacements:o.z.array(o.z.object({old_str:o.z.string().min(1,"old_str cannot be empty"),new_str:o.z.string(),match_mode:o.z.enum(["unique","all"]).optional()})).min(1,"At least one replacement required"),fuzzy_match:o.z.boolean().optional()}).transform(h).refine(p,{message:"path or documentId required"})).min(1,"At least one operation required"),fuzzy_match:o.z.boolean().optional().default(!0),comment:o.z.string()}),exports.DeleteFileSchema=o.z.object({path:o.z.string(),comment:o.z.string()}),exports.DeleteFilesSchema=o.z.object({paths:o.z.array(o.z.string()).optional(),operations:o.z.array(o.z.object({path:o.z.string().optional(),documentId:u.optional()}).transform(h).refine(p,{message:"path or documentId required"})).optional(),comment:o.z.string()}).refine(e=>e.paths&&!e.operations||!e.paths&&e.operations,{message:"paths or operations required"}).refine(e=>e.paths?.length||e.operations?.length,{message:"path/operation required"}),exports.FileHistorySchema=o.z.object({path:o.z.string(),limit:o.z.number().min(1).max(100).default(10),showDiff:o.z.boolean().default(!1),showTraceability:o.z.boolean().default(!0),branch:o.z.string().optional(),commit:o.z.string().optional(),since:o.z.string().optional()}),exports.FileRecoverSchema=o.z.object({path:o.z.string(),commitHash:o.z.string(),createBackup:o.z.boolean().default(!0)}),exports.MergePreviewSchema=o.z.object({requestId:d,format:o.z.enum(["summary","unified"]).default("summary").describe("summary = per-file counts; unified = the diff the merge would add to your branch"),path:o.z.string().optional().describe('Optional git pathspec to scope the preview (e.g. "src/hud.css", "src/", "**/*.ts")')}),exports.RequestDiffSchema=o.z.object({requestId:d,format:o.z.enum(["summary","unified"]).default("summary"),path:o.z.string().optional()}),exports.QueryHistorySchema=o.z.object({queryType:o.z.enum(["file-history","task-file-history","request-file-history","recover","blame"],{errorMap:()=>({message:"Invalid queryType. Valid options: file-history, task-file-history, request-file-history, recover, blame"})}),fileHistory:o.z.object({path:o.z.string(),limit:o.z.number().min(1).max(100).default(10),showDiff:o.z.boolean().default(!1),showTraceability:o.z.boolean().default(!0),branch:o.z.string().optional(),commit:o.z.string().optional(),since:o.z.string().optional()}).optional(),taskHistory:o.z.object({taskId:l,showDiff:o.z.boolean().optional()}).optional(),requestHistory:o.z.object({requestId:d,detailLevel:o.z.enum(["summary","detailed"]).default("summary"),taskId:l.optional(),showDiff:o.z.boolean().optional(),fileFilter:o.z.string().optional()}).optional(),recover:o.z.object({path:o.z.string(),commitHash:o.z.string().optional(),createBackup:o.z.boolean().default(!0)}).optional(),blame:o.z.object({path:o.z.string(),lines:o.z.string().optional(),branch:o.z.string().optional()}).optional()}).refine(e=>"file-history"===e.queryType?e.fileHistory&&!e.requestHistory&&!e.recover:"task-file-history"===e.queryType?e.taskHistory&&!e.fileHistory&&!e.requestHistory&&!e.recover:"request-file-history"===e.queryType?e.requestHistory&&!e.fileHistory&&!e.recover:"recover"===e.queryType?e.recover&&!e.fileHistory&&!e.requestHistory&&!e.blame:"blame"===e.queryType&&e.blame&&!e.fileHistory&&!e.requestHistory&&!e.recover,{message:"Invalid query data"}),exports.SearchSchema=o.z.object({needle:o.z.string().optional(),directory:o.z.string().optional(),directories:o.z.array(o.z.string()).max(8).optional(),options:o.z.object({caseSensitive:o.z.boolean().optional(),fileExtension:o.z.string().optional(),maxResults:o.z.number().optional(),useRegex:o.z.boolean().optional(),searchIn:o.z.enum(["content","filename","both"]).default("content").optional(),contextLines:o.z.number().min(0).optional(),levels:o.z.number().min(1).max(4).optional(),sortBy:o.z.enum(["name","modified","size","type"]).optional()}).optional()}),exports.ListTasksSchema=o.z.object({requestId:d,filters:o.z.object({status:o.z.enum(["pending","in_progress","ready_for_review","completed","canceled","reverted"]).optional(),limit:o.z.number().min(1).max(100).default(20),offset:o.z.number().min(0).default(0),sortBy:o.z.enum(["created","updated"]).default("updated"),sortDirection:o.z.enum(["asc","desc"]).default("desc")}).optional()}),exports.ListRequestsSchema=o.z.object({filters:o.z.object({type:exports.RequestTypeEnum.optional(),status:exports.RequestStatusFilterEnum.optional(),planDocumentId:o.z.string().optional(),scheduleDocumentId:o.z.string().optional().describe("Requests a schedule fired: that schedule document."),questDocumentId:o.z.string().optional().describe("Legacy name of scheduleDocumentId."),dateFrom:o.z.string().optional().describe("Only requests with activity from this date on (YYYY-MM-DD means that whole day in the user's clock, or an ISO timestamp)."),dateTo:o.z.string().optional().describe("Only requests with activity up to this date (YYYY-MM-DD includes the whole day)."),limit:o.z.number().min(1).max(100).default(20),offset:o.z.number().min(0).default(0),sortBy:o.z.enum(["created","updated"]).default("updated"),sortDirection:o.z.enum(["asc","desc"]).default("desc")}).optional()}),exports.GetRequestInformationSchema=o.z.object({requestId:d}),exports.GetTaskInformationSchema=o.z.object({taskId:l}),exports.CompleteTaskSchema=o.z.object({taskId:l,summary:o.z.string()}),exports.TaskInspectSchema=o.z.object({operation:o.z.enum(["get-info","list"]),taskId:l.optional(),requestId:d.optional(),status:o.z.enum(["pending","in_progress","ready_for_review","completed","canceled","reverted"]).optional(),limit:o.z.number().min(1).max(100).default(20),offset:o.z.number().min(0).default(0),sortBy:o.z.enum(["created","updated"]).default("updated"),sortDirection:o.z.enum(["asc","desc"]).default("desc")}).superRefine((e,t)=>{"get-info"!==e.operation||e.taskId||t.addIssue({code:"custom",message:'taskId is required for get-info. Example: { "operation": "get-info", "taskId": "req000001#01" }'}),"list"!==e.operation||e.requestId||t.addIssue({code:"custom",message:'requestId is required for list. Example: { "operation": "list", "requestId": "req000001" }'})})
5619
+ const f=o.z.string().min(1).describe("OpenCode session ID")
5620
+ exports.SubagentOperationsSchema=o.z.object({sessionId:f.optional(),operation:o.z.enum(["spawn","continue","check-status","abort","read-messages","list-sessions"]),prompt:o.z.string().min(1).describe("Instructions for the subagent (required for spawn and continue)").optional(),agent:o.z.string().default("work").refine(e=>(0,s.isValidAgent)(e),{message:"Invalid agent. Check tool description for available agents."}).describe("The subagent type to spawn (see tool description for available agents)").optional(),description:o.z.string().max(60).describe("Brief label for the UI (max 60 chars, spawn only)").optional(),requestId:o.z.string().describe("Request ID: associates work (spawn) or filters results (list-sessions)").optional(),allowParallel:o.z.boolean().describe("Allow spawning even if request already has active workers (spawn only)").optional(),useExistingSession:o.z.string().describe("Existing session ID to send prompt to instead of creating new session (spawn only)").optional(),limit:o.z.number().min(1).max(100).describe("Max items to return (read-messages: max 50, list-sessions: max 100)").optional(),compact:o.z.boolean().describe("read-messages: return a one-line index of EACH message with tool-call markers (the subagent`s trajectory at a glance: which tools ran, in what order, which failed), instead of full text. Use to see what a subagent actually DID, then `select` one for detail.").optional(),select:o.z.number().min(1).describe("read-messages: return ONLY this message number (from the compact list) in full structured detail: each tool call as {tool, input, status, output}, plus its text. The objective record of one step.").optional(),activeOnly:o.z.boolean().describe("Only show sessions that are currently active/busy (list-sessions only)").optional(),minTokens:o.z.number().min(0).describe("Only show sessions with at least this many tokens (list-sessions only)").optional(),maxTokens:o.z.number().min(0).describe("Only show sessions with at most this many tokens (list-sessions only)").optional(),maxAgeHours:o.z.number().min(0).describe("Only show sessions newer than X hours (list-sessions only)").optional()}).refine(e=>"spawn"===e.operation?!!e.prompt:"continue"===e.operation?!!e.prompt&&!!e.sessionId:"check-status"===e.operation||"abort"===e.operation||"read-messages"===e.operation?!!e.sessionId:"list-sessions"===e.operation,{message:"spawn requires prompt; continue requires prompt+sessionId; check-status/abort/read-messages require sessionId"}),exports.ResearchFanoutSchema=o.z.object({goal:o.z.string().min(1).optional().describe("What to research; passed to every angle. Required to START a run."),angles:o.z.array(o.z.string()).optional().describe("Research angles to fan out over. Omit to use the default set (data-model, call-sites, prior-art/history, external/web, test-surface)."),planId:o.z.string().optional().describe("Plan document to reference the research report from when the run completes."),checkRunId:o.z.string().optional().describe("Pass a runId from a previous start to CHECK that run live progress instead of starting a new one.")}).refine(e=>!(!e.goal||!e.goal.trim())||!!e.checkRunId,{message:"Provide goal to start a run, or checkRunId to check one."}),exports.PlannerOpsSchema=o.z.object({operation:o.z.enum(["request","check-status","list","end"]),sessionId:f.optional(),prompt:o.z.string().min(1).describe("request (required): what to plan").optional(),description:o.z.string().max(60).describe("request: a short label").optional(),userRequested:o.z.boolean().describe("request: true only when the user asked for this plan themselves").optional(),userStarts:o.z.boolean().describe("request: the user said they will start the plan themselves").optional(),documentId:o.z.string().describe("request: an existing plan to evolve in place; end: the plan whose planner to end").optional(),activeOnly:o.z.boolean().optional(),limit:o.z.number().min(1).max(100).optional()}).refine(e=>"request"===e.operation?!!e.prompt:"check-status"===e.operation?!!e.sessionId:"list"===e.operation||"end"===e.operation&&(!!e.sessionId||!!e.documentId),{message:"request requires prompt; check-status requires sessionId; end requires sessionId or documentId"}),exports.InsertLinesSchema=o.z.object({operations:o.z.array(o.z.object({path:o.z.string().optional(),documentId:u.optional(),insertions:o.z.array(o.z.object({type:o.z.enum(["before","after","between"]),line:o.z.number().optional(),afterLine:o.z.number().optional(),beforeLine:o.z.number().optional(),content:o.z.union([o.z.string(),o.z.array(o.z.string())])}).refine(e=>"between"===e.type?void 0!==e.afterLine&&void 0!==e.beforeLine&&void 0===e.line:void 0!==e.line&&void 0===e.afterLine&&void 0===e.beforeLine,{message:"Invalid line parameters"}))}).transform(h).refine(p,{message:"path or documentId required"})),comment:o.z.string()}),exports.ReplaceLinesSchema=o.z.object({operations:o.z.array(o.z.object({path:o.z.string().optional(),documentId:u.optional(),replacements:o.z.array(o.z.object({lines:o.z.string(),content:o.z.union([o.z.string(),o.z.array(o.z.string())])}))}).transform(h).refine(p,{message:"path or documentId required"})),comment:o.z.string()}),exports.CreateDocumentSchema=o.z.object({requestId:d.optional(),filename:o.z.string().refine(e=>/\.(md|html?)$/i.test(e),{message:"Filename must end in .md (prose) or .html (a rendered page)"}),content:o.z.string(),comment:o.z.string(),scheduleIntervalSeconds:o.z.number().int().min(300).describe("Fire interval in seconds (min 300). Setting this makes the document a SCHEDULE: the runner periodically asks the alchemist to read it and create one linked request. 86400 = daily. Prefer scheduleAtTimes when the goal wants a time of day.").optional(),scheduleAtTimes:o.z.string().describe("Local time(s) of day to fire, e.g. '09:00' or '09:00,17:00'. Setting this makes the document a SCHEDULE that runs at that clock time instead of on an interval, and it starts at the next such time (never the moment it is created).").optional(),scheduleOnDays:o.z.string().describe("Which days scheduleAtTimes applies to: 'weekdays', 'weekends', or names like 'mon,thu'. Omit for every day.").optional(),schedulePrompt:o.z.string().describe('What each firing should do -- the instruction the alchemist receives per tick (e.g. "validate quotes.ndjson and file a short report; flag the user only on real breakage").').optional(),scheduleMaxPerDay:o.z.number().int().min(1).describe("Cap on requests it files per day (structural guard); only when the user named one. A goal with a target keeps reading it past the cap.").optional(),scheduleMaxInFlight:o.z.number().int().min(1).describe("Cap on live linked requests before firings pause (structural guard). Default 1.").optional(),target:exports.TargetConditionsSchema.optional(),scheduleBudgetUsd:o.z.number().positive().max(1e5).optional(),userSaid:o.z.string().max(600).optional()}),exports.SearchDocumentsSchema=o.z.object({query:o.z.string(),requestId:d.optional(),includeArchived:o.z.boolean().default(!1),maxResults:o.z.number().min(1).max(100).default(20),dateFrom:o.z.string().optional(),dateTo:o.z.string().optional(),searchIn:o.z.enum(["content","filename","both"]).default("both")}),exports.DocumentOperationsSchema=o.z.object({operation:o.z.enum(["create","update","search","create-snapshot","get-history","get-version","restore-version","archive","unarchive","list-annotations","create-annotation","reply-to-annotation","resolve-annotation","create-artifact-annotation","propose-standard"]),standardRules:o.z.array(o.z.object({text:o.z.string().min(1).max(600),section:o.z.string().min(1).max(120),checked:o.z.boolean(),kinds:o.z.array(o.z.enum(["code","engineering","writing","drive"])).max(4).optional()})).min(1).max(12).optional(),documentId:u.optional(),requestId:d.optional(),filename:o.z.string().optional(),content:o.z.string().optional(),comment:o.z.string().optional(),scheduleIntervalSeconds:o.z.number().int().min(300).optional(),scheduleAtTimes:o.z.string().optional(),scheduleOnDays:o.z.string().optional(),schedulePrompt:o.z.string().optional(),scheduleMaxPerDay:o.z.number().int().min(1).optional(),scheduleMaxInFlight:o.z.number().int().min(1).optional(),target:exports.TargetConditionsSchema.optional(),scheduleEnabled:o.z.boolean().optional().describe("update: false pauses, true resumes (with scheduleReason); archive only a finished goal."),scheduleBudgetUsd:o.z.number().positive().max(1e5).nullable().optional().describe("Dollars at list price for the whole goal (its requests and your turns on it); at it, the goal stops until the user allows more. null removes it."),userSaid:o.z.string().min(8).max(600).optional().describe("With scheduleBudgetUsd or target: the user's words, exact."),scheduleReason:o.z.string().optional().describe("Why paused or resumed; the user reads it."),query:o.z.string().optional(),includeArchived:o.z.boolean().default(!1),maxResults:o.z.number().min(1).max(100).default(20),dateFrom:o.z.string().optional(),dateTo:o.z.string().optional(),searchIn:o.z.enum(["content","filename","both"]).default("both"),replacements:o.z.array(o.z.object({old_str:o.z.string(),new_str:o.z.string()})).optional(),mode:o.z.enum(["unique","all"]).optional(),versionLabel:o.z.string().optional(),changeSummary:o.z.string().optional(),versionNumber:o.z.number().int().min(1).optional(),selectedText:o.z.string().optional(),prefixContext:o.z.string().optional(),suffixContext:o.z.string().optional(),lineHint:o.z.number().int().optional(),body:o.z.string().optional(),annotationId:o.z.string().optional(),ref:o.z.string().optional(),file:o.z.string().optional(),line:o.z.union([o.z.number().int(),o.z.string()]).optional()}).superRefine((e,t)=>{const r=e.operation
5598
5621
  "propose-standard"!==r||e.standardRules&&e.standardRules.length||t.addIssue({code:"custom",message:"standardRules is required for propose-standard: [{ text, section, checked, kinds? }]"}),["create-snapshot","get-history","get-version","restore-version","list-annotations","create-annotation","propose-standard"].includes(r)&&!e.documentId&&t.addIssue({code:"custom",message:`documentId is required for '${r}'. Example: { "operation": "${r}", "documentId": "doc000001" }`}),"create"===r&&(e.filename?/\.(md|html?)$/i.test(e.filename)||t.addIssue({code:"custom",message:"Filename must end in .md (prose) or .html (a rendered page)"}):t.addIssue({code:"custom",message:"filename is required for create (must end in .md or .html)"}),e.content||t.addIssue({code:"custom",message:"content is required for create"})),"search"!==r||e.query||t.addIssue({code:"custom",message:'query is required for search. Example: { "operation": "search", "query": "search term" }'}),"get-version"!==r&&"restore-version"!==r||e.versionNumber||t.addIssue({code:"custom",message:`versionNumber is required for '${r}'`}),"create-annotation"===r&&(e.selectedText||t.addIssue({code:"custom",message:"selectedText is required for create-annotation"}),e.body||t.addIssue({code:"custom",message:"body is required for create-annotation"})),"reply-to-annotation"===r&&(e.annotationId||t.addIssue({code:"custom",message:"annotationId is required for reply-to-annotation"}),e.body||t.addIssue({code:"custom",message:"body is required for reply-to-annotation"})),"resolve-annotation"!==r||e.annotationId||t.addIssue({code:"custom",message:"annotationId is required for resolve-annotation"}),"create-artifact-annotation"===r&&(e.ref||t.addIssue({code:"custom",message:'ref is required for create-artifact-annotation. Example: { "operation": "create-artifact-annotation", "ref": "file:src/main.cpp", "line": 42, "body": "..." }'}),e.body||t.addIssue({code:"custom",message:"body is required for create-artifact-annotation"}))})
5599
- const f=d
5600
- exports.PlanReadSchema=n.z.object({operation:n.z.enum(["get","get-active","list","get-history","get-requests"]),planId:f.optional(),searchQuery:n.z.string().optional(),limit:n.z.number().min(1).max(100).default(20),offset:n.z.number().min(0).default(0),sortBy:n.z.enum(["createdAt","updatedAt","filename"]).default("updatedAt"),sortDirection:n.z.enum(["ASC","DESC"]).default("DESC")}).superRefine((e,t)=>{["get","get-history","get-requests"].includes(e.operation)&&!e.planId&&t.addIssue({code:"custom",message:`planId is required for '${e.operation}'. Example: { "operation": "${e.operation}", "planId": "plan000001" }`})}),exports.PlanWriteSchema=n.z.object({operation:n.z.enum(["create","update","append","replace","create-snapshot","restore"]),planId:f.optional(),kind:n.z.enum(["plan"]).default("plan").describe("Document kind to create. Plans only."),content:n.z.string().optional(),name:n.z.string().optional().describe("Plan name (used in filename for create; optional new name for update)."),old_str:n.z.string().optional().describe("Text to find in the plan (for replace)"),new_str:n.z.string().optional().describe("Replacement text (for replace)"),versionLabel:n.z.string().optional(),changeSummary:n.z.string().optional(),versionNumber:n.z.number().int().min(1).optional()}).superRefine((e,t)=>{const r=e.operation
5601
- "create"===r?(e.name||t.addIssue({code:"custom",message:"name is required for 'create'. Letters, numbers, hyphens, underscores only."}),void 0===e.content&&t.addIssue({code:"custom",message:"content is required for 'create' (use empty string for an empty body)."})):e.planId||t.addIssue({code:"custom",message:`planId is required for '${r}'.`}),"append"!==r||e.content||t.addIssue({code:"custom",message:'content is required for \'append\'. Example: { "operation": "append", "planId": "plan000001", "content": "..." }'}),"update"===r&&(void 0!==e.content||e.name||t.addIssue({code:"custom",message:"update requires 'content' and/or 'name'."})),"replace"===r&&(e.old_str||t.addIssue({code:"custom",message:'old_str is required for replace. Example: { "operation": "replace", "planId": "plan000001", "old_str": "find this", "new_str": "replace with" }'}),void 0===e.new_str&&t.addIssue({code:"custom",message:"new_str is required for replace"})),"restore"!==r||e.versionNumber||t.addIssue({code:"custom",message:'versionNumber is required for restore. Example: { "operation": "restore", "planId": "plan000001", "versionNumber": 1 }'})}),exports.RevertRequestSchema=n.z.object({requestId:l,reason:n.z.string(),confirmDestructive:n.z.boolean().optional()}),exports.ModifyFileSchema=n.z.object({operations:n.z.array(n.z.object({path:n.z.string().optional(),documentId:d.optional(),operationType:n.z.enum(["replace-string","insert-lines","replace-lines","delete-string","delete-lines"]),replaceString:n.z.object({replacements:n.z.array(n.z.object({old_str:n.z.string(),new_str:n.z.string()})),mode:n.z.enum(["unique","all"]).optional()}).optional(),insertLines:n.z.object({insertions:n.z.array(n.z.object({type:n.z.enum(["before","after","between"]),line:n.z.number().optional(),afterLine:n.z.number().optional(),beforeLine:n.z.number().optional(),content:n.z.union([n.z.string(),n.z.array(n.z.string())])}).refine(e=>"between"===e.type?void 0!==e.afterLine&&void 0!==e.beforeLine&&void 0===e.line:void 0!==e.line&&void 0===e.afterLine&&void 0===e.beforeLine,{message:"Invalid line parameters"}))}).optional(),replaceLines:n.z.object({replacements:n.z.array(n.z.object({lines:n.z.string(),content:n.z.union([n.z.string(),n.z.array(n.z.string())])}))}).optional(),deleteString:n.z.object({patterns:n.z.array(n.z.string()),mode:n.z.enum(["all","unique"]).optional()}).optional(),deleteLines:n.z.object({lines:n.z.string()}).optional()}).transform(u).refine(h,{message:"path or documentId required"}).refine(e=>"replace-string"===e.operationType?e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteString&&!e.deleteLines:"insert-lines"===e.operationType?e.insertLines&&!e.replaceString&&!e.replaceLines&&!e.deleteString&&!e.deleteLines:"replace-lines"===e.operationType?e.replaceLines&&!e.replaceString&&!e.insertLines&&!e.deleteString&&!e.deleteLines:"delete-string"===e.operationType?e.deleteString&&!e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteLines:"delete-lines"===e.operationType&&e.deleteLines&&!e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteString,{message:"Invalid operation data"})),comment:n.z.string()}),exports.ManageFilesSchema=n.z.object({operations:n.z.array(n.z.object({operationType:n.z.enum(["create-directory","move-files","delete-files","get-file-info"]),createDirectory:n.z.object({path:n.z.string()}).optional(),moveFiles:n.z.object({moves:n.z.array(n.z.object({source:n.z.string(),destination:n.z.string()}))}).optional(),deleteFiles:n.z.object({targets:n.z.array(n.z.object({path:n.z.string().optional(),documentId:d.optional()}).transform(u).refine(h,{message:"path or documentId required"}))}).optional(),getFileInfo:n.z.object({path:n.z.string()}).optional()}).refine(e=>"create-directory"===e.operationType?e.createDirectory&&!e.moveFiles&&!e.deleteFiles&&!e.getFileInfo:"move-files"===e.operationType?e.moveFiles&&!e.createDirectory&&!e.deleteFiles&&!e.getFileInfo:"delete-files"===e.operationType?e.deleteFiles&&!e.createDirectory&&!e.moveFiles&&!e.getFileInfo:"get-file-info"===e.operationType&&e.getFileInfo&&!e.createDirectory&&!e.moveFiles&&!e.deleteFiles,{message:"Invalid operation data"})),comment:n.z.string()}),exports.RequestOperationsSchema=n.z.object({requestId:l.optional(),operation:n.z.enum(["update","activate","complete","merge","revert","reopen","get-info","list","search","status","cancel","hold","delete-empty","list-areas","update-areas","wait-on","clear-wait","premise-block","dispute-criterion","hand-over","bring-main-in","check-target","round-piece"]),planId:n.z.string().max(64).optional().describe("status / check-target: a plan's thread."),criterion:n.z.string().optional(),reason:n.z.string().optional().describe('cancel, revert, reopen, wait-on: why, to the user ("you"), in their language (a replacing request named). premise-block (required): what the request builds on that the project lacks; not what it adds, not unclear wording (ask instead).'),userSaid:n.z.string().min(8).max(600).optional().describe("The user's words asking for this, exact (checked). Required for activate, cancel of finished work waiting on them, and reopen with a question pending on them."),waitsOn:n.z.string().optional(),update:n.z.preprocess(e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e,n.z.object({userSaid:n.z.string().min(8).max(600).optional().describe("The user's words asking for this change, exact; a worker narrows or rewords its own request only with them."),budget:n.z.number().positive().max(1e5).nullable().optional().describe("The budget the user named for this request's thread (or plan), dollars at list price, their words in userSaid; null removes it."),target:exports.TargetConditionsSchema.optional(),estimate:n.z.number().positive().max(1e5).optional().describe("Expected cost, dollars at list price."),removesCriteria:n.z.boolean().optional().describe("true to delete the criteria your list leaves out; otherwise a shorter list is refused."),arcName:n.z.string().min(2).max(120).optional().describe("The thread's name, two to five plain words (\"Weekly menu app\"); set once, never over the user's."),title:n.z.string().optional(),description:n.z.string().optional(),process:n.z.string().nullable().optional().describe("A workflow process by name, or null; drafts only."),type:exports.SettableRequestTypeEnum.optional(),acceptanceCriteria:n.z.array(n.z.union([n.z.string(),n.z.object({description:n.z.string().min(1),beforeMerge:n.z.boolean().optional(),command:n.z.string().min(1).max(500).optional().describe("With the criterion's key: replaces its command, and the old line is kept on the record beside it. A worker replaces one that cannot pass where it runs with a line that checks the same thing, never less; the user's own command only with their answer in userSaid."),environment:n.z.string().min(1).max(120).optional().describe("As on create_request; set it instead of dropping a command the box cannot run."),kind:n.z.enum(["objective","subjective","gate"]),baseline:r(exports.BaselineSchema).optional(),key:n.z.string().optional().describe("The key of a criterion you reword (it keeps its verdicts); omit for a new one.")})])).optional().describe("Replaces the whole list; items as on create_request.")})).optional(),areas:n.z.array(n.z.string()).max(3).optional().describe("update-areas: up to 3 replacing the current ones; [] clears."),complete:n.z.preprocess(e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e,n.z.object({change:n.z.preprocess(i,n.z.string().min(3).max(200).optional()).describe('On a round (its description opens "Round N of req######"), instead of summary while the round is open: what this one change did, in one line. The user reads it under the message that asked for it.'),summary:n.z.preprocess(i,n.z.string().optional()).describe('Markdown the user reads when it lands. First line: one sentence with the answer (if the request asked a question) or what changed. Then, only if there is more, one short "- " line per thing; no paragraphs. Never "tested" or "verified" when that failed. It replaces earlier summaries (after rework it covers the whole request) and stays after sign-off, so it says what was delivered, not what waits for the user. On a round it is written once, when you are told the round is being completed; until then pass change.'),replacesSummary:n.z.boolean().optional().describe("Required on a re-completion: the summary covers everything, fixes included."),notChecked:n.z.preprocess(i,n.z.string().min(3).max(160).optional()).describe('What you did not check that the user could assume you did ("the page on a phone"); the card leads with it. Not what registered checks run or say they leave out (the card shows those).'),show:n.z.preprocess(e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e,n.z.object({commands:n.z.array(n.z.string().min(1).max(400)).max(5).optional().describe("Command lines that show the result working. AlchemyLab runs each in a box on the work as it was and on the completed work; the user sees both."),artifact:n.z.string().min(1).max(200).optional().describe("A picture, page or document on the record: a result's address, a document id (doc000012) or asset:<file>.")}).optional()).describe("Optional: something more to show with the finished result. What the request already delivered is shown by itself."),worthKnowing:n.z.array(n.z.string().min(10)).max(5).optional().describe("What the user would regret not knowing, one per entry (a discovery, caveat, side effect, follow-up); always one when what was asked was already true or turned out different. Not the summary again; subject first."),guidance:n.z.array(n.z.object({body:n.z.string().min(10).max(800).describe('One fact or instruction for the next agent ("calc.py is generated from ops.json: edit ops.json and regenerate.")'),files:n.z.array(n.z.string().min(1)).min(1).max(8).optional().describe("Files or folders (globs) it is pinned to; without them (userSaid only) the whole project."),evidence:n.z.string().min(1).max(1500).optional().describe("What shows it (command and output, file); not with userSaid."),userSaid:n.z.string().min(8).max(600).optional().describe("A correction of the user's that should hold later: their words, exact.")}).refine(e=>!!e.userSaid||!!e.files?.length&&!!e.evidence,{message:"a trap needs files and evidence; a correction of the user's needs userSaid"})).max(2).optional().describe("A trap the next agent in these files would hit too, or a user correction, proposed as guidance. Not taste, not request-specific, not already guidance. Usually none."),skipTestsReason:exports.skipTestsReasonSchema,skipTests:exports.skipTestsSchema,criteriaComments:n.z.array(n.z.object({key:n.z.string().min(1),comment:n.z.string().min(1),verify:n.z.array(n.z.string().min(1)).max(4).optional().describe("Commands that prove it in the sealed acceptance box (a grep, a targeted test, a screenshot into .visual-check/), judged on their output. Clean checkout of your commit, dependencies installed, nothing built: a check needing a build runs it in the same command. No git, no network, no branching on whether a tool exists. A proof you saw pass on this commit, written exactly as you ran it, is reused."),testFiles:n.z.array(n.z.string().min(1)).max(10).optional().describe("With verify, when it runs just these tests (not the whole suite): their repo paths. Only the user changes a test a promise names.")})).optional().describe("One entry per criterion, keyed as your pickup lists it: what you did and how you saw it hold."),afterRun:n.z.boolean().optional().describe("Call `run` with your final check, then this complete in the SAME response: it completes only if that run passes."),couldNotCheck:n.z.array(n.z.string().min(1)).max(20).optional().describe("Drives only: keys of claims you could not check (reason in criteriaComments); they read as unchecked. Stamp the rest with record_criteria_verification.")})).optional(),merge:n.z.preprocess(e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e,n.z.object({verifications:n.z.array(n.z.object({key:n.z.string().min(2).max(4),evidence:n.z.string().min(1)})).min(1)})).optional(),revert:n.z.object({reason:n.z.string(),confirmDestructive:n.z.boolean().optional()}).optional(),list:n.z.object({filters:n.z.object({type:exports.RequestTypeEnum.optional(),status:exports.RequestStatusFilterEnum.optional(),planDocumentId:n.z.string().optional(),scheduleDocumentId:n.z.string().optional(),questDocumentId:n.z.string().optional(),dateFrom:n.z.string().optional(),dateTo:n.z.string().optional(),limit:n.z.number().min(1).max(100).default(20),offset:n.z.number().min(0).default(0),sortBy:n.z.enum(["created","updated"]).default("updated"),sortDirection:n.z.enum(["asc","desc"]).default("desc")}).optional()}).optional(),search:n.z.object({query:n.z.string().min(1),searchIn:n.z.enum(["title","description","criteria","all"]).default("all"),filters:n.z.object({type:exports.RequestTypeEnum.optional(),status:exports.RequestStatusFilterEnum.optional(),planDocumentId:n.z.string().optional(),scheduleDocumentId:n.z.string().optional(),questDocumentId:n.z.string().optional(),dateFrom:n.z.string().optional(),dateTo:n.z.string().optional(),limit:n.z.number().min(1).max(100).default(20),offset:n.z.number().min(0).default(0)}).optional()}).optional()}).superRefine((e,t)=>{e.requestId
5622
+ const m=u
5623
+ exports.PlanReadSchema=o.z.object({operation:o.z.enum(["get","get-active","list","get-history","get-requests"]),planId:m.optional(),searchQuery:o.z.string().optional(),limit:o.z.number().min(1).max(100).default(20),offset:o.z.number().min(0).default(0),sortBy:o.z.enum(["createdAt","updatedAt","filename"]).default("updatedAt"),sortDirection:o.z.enum(["ASC","DESC"]).default("DESC")}).superRefine((e,t)=>{["get","get-history","get-requests"].includes(e.operation)&&!e.planId&&t.addIssue({code:"custom",message:`planId is required for '${e.operation}'. Example: { "operation": "${e.operation}", "planId": "plan000001" }`})}),exports.PlanWriteSchema=o.z.object({operation:o.z.enum(["create","update","append","replace","create-snapshot","restore"]),planId:m.optional(),kind:o.z.enum(["plan"]).default("plan").describe("Document kind to create. Plans only."),content:o.z.string().optional(),name:o.z.string().optional().describe("Plan name (used in filename for create; optional new name for update)."),old_str:o.z.string().optional().describe("Text to find in the plan (for replace)"),new_str:o.z.string().optional().describe("Replacement text (for replace)"),versionLabel:o.z.string().optional(),changeSummary:o.z.string().optional(),versionNumber:o.z.number().int().min(1).optional()}).superRefine((e,t)=>{const r=e.operation
5624
+ "create"===r?(e.name||t.addIssue({code:"custom",message:"name is required for 'create'. Letters, numbers, hyphens, underscores only."}),void 0===e.content&&t.addIssue({code:"custom",message:"content is required for 'create' (use empty string for an empty body)."})):e.planId||t.addIssue({code:"custom",message:`planId is required for '${r}'.`}),"append"!==r||e.content||t.addIssue({code:"custom",message:'content is required for \'append\'. Example: { "operation": "append", "planId": "plan000001", "content": "..." }'}),"update"===r&&(void 0!==e.content||e.name||t.addIssue({code:"custom",message:"update requires 'content' and/or 'name'."})),"replace"===r&&(e.old_str||t.addIssue({code:"custom",message:'old_str is required for replace. Example: { "operation": "replace", "planId": "plan000001", "old_str": "find this", "new_str": "replace with" }'}),void 0===e.new_str&&t.addIssue({code:"custom",message:"new_str is required for replace"})),"restore"!==r||e.versionNumber||t.addIssue({code:"custom",message:'versionNumber is required for restore. Example: { "operation": "restore", "planId": "plan000001", "versionNumber": 1 }'})}),exports.RevertRequestSchema=o.z.object({requestId:d,reason:o.z.string(),confirmDestructive:o.z.boolean().optional()}),exports.ModifyFileSchema=o.z.object({operations:o.z.array(o.z.object({path:o.z.string().optional(),documentId:u.optional(),operationType:o.z.enum(["replace-string","insert-lines","replace-lines","delete-string","delete-lines"]),replaceString:o.z.object({replacements:o.z.array(o.z.object({old_str:o.z.string(),new_str:o.z.string()})),mode:o.z.enum(["unique","all"]).optional()}).optional(),insertLines:o.z.object({insertions:o.z.array(o.z.object({type:o.z.enum(["before","after","between"]),line:o.z.number().optional(),afterLine:o.z.number().optional(),beforeLine:o.z.number().optional(),content:o.z.union([o.z.string(),o.z.array(o.z.string())])}).refine(e=>"between"===e.type?void 0!==e.afterLine&&void 0!==e.beforeLine&&void 0===e.line:void 0!==e.line&&void 0===e.afterLine&&void 0===e.beforeLine,{message:"Invalid line parameters"}))}).optional(),replaceLines:o.z.object({replacements:o.z.array(o.z.object({lines:o.z.string(),content:o.z.union([o.z.string(),o.z.array(o.z.string())])}))}).optional(),deleteString:o.z.object({patterns:o.z.array(o.z.string()),mode:o.z.enum(["all","unique"]).optional()}).optional(),deleteLines:o.z.object({lines:o.z.string()}).optional()}).transform(h).refine(p,{message:"path or documentId required"}).refine(e=>"replace-string"===e.operationType?e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteString&&!e.deleteLines:"insert-lines"===e.operationType?e.insertLines&&!e.replaceString&&!e.replaceLines&&!e.deleteString&&!e.deleteLines:"replace-lines"===e.operationType?e.replaceLines&&!e.replaceString&&!e.insertLines&&!e.deleteString&&!e.deleteLines:"delete-string"===e.operationType?e.deleteString&&!e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteLines:"delete-lines"===e.operationType&&e.deleteLines&&!e.replaceString&&!e.insertLines&&!e.replaceLines&&!e.deleteString,{message:"Invalid operation data"})),comment:o.z.string()}),exports.ManageFilesSchema=o.z.object({operations:o.z.array(o.z.object({operationType:o.z.enum(["create-directory","move-files","delete-files","get-file-info"]),createDirectory:o.z.object({path:o.z.string()}).optional(),moveFiles:o.z.object({moves:o.z.array(o.z.object({source:o.z.string(),destination:o.z.string()}))}).optional(),deleteFiles:o.z.object({targets:o.z.array(o.z.object({path:o.z.string().optional(),documentId:u.optional()}).transform(h).refine(p,{message:"path or documentId required"}))}).optional(),getFileInfo:o.z.object({path:o.z.string()}).optional()}).refine(e=>"create-directory"===e.operationType?e.createDirectory&&!e.moveFiles&&!e.deleteFiles&&!e.getFileInfo:"move-files"===e.operationType?e.moveFiles&&!e.createDirectory&&!e.deleteFiles&&!e.getFileInfo:"delete-files"===e.operationType?e.deleteFiles&&!e.createDirectory&&!e.moveFiles&&!e.getFileInfo:"get-file-info"===e.operationType&&e.getFileInfo&&!e.createDirectory&&!e.moveFiles&&!e.deleteFiles,{message:"Invalid operation data"})),comment:o.z.string()}),exports.RequestOperationsSchema=o.z.object({requestId:d.optional(),operation:o.z.enum(["update","activate","complete","merge","revert","reopen","get-info","list","search","status","cancel","hold","delete-empty","list-areas","update-areas","wait-on","clear-wait","premise-block","dispute-criterion","hand-over","bring-main-in","check-target","round-piece"]),planId:o.z.string().max(64).optional().describe("status / check-target: a plan's thread."),criterion:o.z.string().optional(),reason:o.z.string().optional().describe('cancel, revert, reopen, wait-on: why, to the user ("you"), in their language (a replacing request named). premise-block (required): what the request builds on that the project lacks; not what it adds, not unclear wording (ask instead).'),userSaid:o.z.string().min(8).max(600).optional().describe("The user's words asking for this, exact (checked). Required for activate, cancel of finished work waiting on them, and reopen with a question pending on them."),waitsOn:o.z.string().optional(),update:o.z.preprocess(e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e,o.z.object({userSaid:o.z.string().min(8).max(600).optional().describe("The user's words asking for this change, exact; a worker narrows or rewords its own request only with them."),budget:o.z.number().positive().max(1e5).nullable().optional().describe("The budget the user named for this request's thread (or plan), dollars at list price, their words in userSaid; null removes it."),target:exports.TargetConditionsSchema.optional(),estimate:o.z.number().positive().max(1e5).optional().describe("Expected cost, dollars at list price."),removesCriteria:o.z.boolean().optional().describe("true to delete the criteria your list leaves out; otherwise a shorter list is refused."),arcName:o.z.string().min(2).max(120).optional().describe("The thread's name, two to five plain words (\"Weekly menu app\"); set once, never over the user's."),title:o.z.string().optional(),description:o.z.string().optional(),process:o.z.string().nullable().optional().describe("A workflow process by name, or null; drafts only."),type:exports.SettableRequestTypeEnum.optional(),acceptanceCriteria:o.z.array(o.z.union([o.z.string(),o.z.object({description:o.z.string().min(1),beforeMerge:o.z.boolean().optional(),command:o.z.string().min(1).max(500).optional().describe("With the criterion's key: replaces its command, and the old line is kept on the record beside it. A worker replaces one that cannot pass where it runs with a line that checks the same thing, never less; the user's own command only with their answer in userSaid."),environment:o.z.string().min(1).max(120).optional().describe("As on create_request; set it instead of dropping a command the box cannot run."),kind:o.z.enum(["objective","subjective","gate"]),baseline:r(exports.BaselineSchema).optional(),key:o.z.string().optional().describe("The key of a criterion you reword (it keeps its verdicts); omit for a new one.")})])).optional().describe("Replaces the whole list; items as on create_request.")})).optional(),areas:o.z.array(o.z.string()).max(3).optional().describe("update-areas: up to 3 replacing the current ones; [] clears."),complete:o.z.preprocess(e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e,o.z.object({change:o.z.preprocess(a,o.z.string().min(3).max(200).optional()).describe('On a round (its description opens "Round N of req######"), instead of summary while the round is open: what this one change did, in one line. The user reads it under the message that asked for it.'),summary:o.z.preprocess(a,o.z.string().optional()).describe('Markdown the user reads when it lands. First line: one sentence with the answer (if the request asked a question) or what changed. Then, only if there is more, one short "- " line per thing; no paragraphs. Never "tested" or "verified" when that failed. It replaces earlier summaries (after rework it covers the whole request) and stays after sign-off, so it says what was delivered, not what waits for the user. On a round it is written once, when you are told the round is being completed; until then pass change.'),replacesSummary:o.z.boolean().optional().describe("Required on a re-completion: the summary covers everything, fixes included."),notChecked:o.z.preprocess(a,o.z.string().min(3).max(160).optional()).describe('What you did not check that the user could assume you did ("the page on a phone"); the card leads with it. Not what registered checks run or say they leave out (the card shows those).'),show:o.z.preprocess(e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e,o.z.object({commands:o.z.array(o.z.string().min(1).max(400)).max(5).optional().describe("Command lines that show the result working. AlchemyLab runs each in a box on the work as it was and on the completed work; the user sees both."),artifact:o.z.string().min(1).max(200).optional().describe("A picture, page or document on the record: a result's address, a document id (doc000012) or asset:<file>.")}).optional()).describe("Optional: something more to show with the finished result. What the request already delivered is shown by itself."),worthKnowing:o.z.array(o.z.string().min(10)).max(5).optional().describe("What the user would regret not knowing, one per entry (a discovery, caveat, side effect, follow-up); always one when what was asked was already true or turned out different. Not the summary again; subject first."),guidance:o.z.array(o.z.object({body:o.z.string().min(10).max(800).describe('One fact or instruction for the next agent ("calc.py is generated from ops.json: edit ops.json and regenerate.")'),files:o.z.array(o.z.string().min(1)).min(1).max(8).optional().describe("Files or folders (globs) it is pinned to; without them (userSaid only) the whole project."),evidence:o.z.string().min(1).max(1500).optional().describe("What shows it (command and output, file); not with userSaid."),userSaid:o.z.string().min(8).max(600).optional().describe("A correction of the user's that should hold later: their words, exact.")}).refine(e=>!!e.userSaid||!!e.files?.length&&!!e.evidence,{message:"a trap needs files and evidence; a correction of the user's needs userSaid"})).max(2).optional().describe("A trap the next agent in these files would hit too, or a user correction, proposed as guidance. Not taste, not request-specific, not already guidance. Usually none."),skipTestsReason:exports.skipTestsReasonSchema,skipTests:exports.skipTestsSchema,criteriaComments:o.z.array(o.z.object({key:o.z.string().min(1),comment:o.z.string().min(1),verify:o.z.array(o.z.string().min(1)).max(4).optional().describe("Commands that prove it in the sealed acceptance box (a grep, a targeted test, a screenshot into .visual-check/), judged on their output. Clean checkout of your commit, dependencies installed, nothing built: a check needing a build runs it in the same command. No git, no network, no branching on whether a tool exists. A proof you saw pass on this commit, written exactly as you ran it, is reused."),testFiles:o.z.array(o.z.string().min(1)).max(10).optional().describe("With verify, when it runs just these tests (not the whole suite): their repo paths. Only the user changes a test a promise names.")})).optional().describe("One entry per criterion, keyed as your pickup lists it: what you did and how you saw it hold."),afterRun:o.z.boolean().optional().describe("Call `run` with your final check, then this complete in the SAME response: it completes only if that run passes."),couldNotCheck:o.z.array(o.z.string().min(1)).max(20).optional().describe("Drives only: keys of claims you could not check (reason in criteriaComments); they read as unchecked. Stamp the rest with record_criteria_verification.")})).optional(),merge:o.z.preprocess(e=>"string"==typeof e?(()=>{try{return JSON.parse(e)}catch{return e}})():e,o.z.object({verifications:o.z.array(o.z.object({key:o.z.string().min(2).max(4),evidence:o.z.string().min(1)})).min(1)})).optional(),revert:o.z.object({reason:o.z.string(),confirmDestructive:o.z.boolean().optional()}).optional(),list:o.z.object({filters:o.z.object({type:exports.RequestTypeEnum.optional(),status:exports.RequestStatusFilterEnum.optional(),planDocumentId:o.z.string().optional(),scheduleDocumentId:o.z.string().optional(),questDocumentId:o.z.string().optional(),dateFrom:o.z.string().optional(),dateTo:o.z.string().optional(),limit:o.z.number().min(1).max(100).default(20),offset:o.z.number().min(0).default(0),sortBy:o.z.enum(["created","updated"]).default("updated"),sortDirection:o.z.enum(["asc","desc"]).default("desc")}).optional()}).optional(),search:o.z.object({query:o.z.string().min(1),searchIn:o.z.enum(["title","description","criteria","all"]).default("all"),filters:o.z.object({type:exports.RequestTypeEnum.optional(),status:exports.RequestStatusFilterEnum.optional(),planDocumentId:o.z.string().optional(),scheduleDocumentId:o.z.string().optional(),questDocumentId:o.z.string().optional(),dateFrom:o.z.string().optional(),dateTo:o.z.string().optional(),limit:o.z.number().min(1).max(100).default(20),offset:o.z.number().min(0).default(0)}).optional()}).optional()}).superRefine((e,t)=>{e.requestId
5602
5625
  const r=e.operation,n={complete:{field:"complete",hint:'Provide: { complete: { summary: "..." } }'},merge:{field:"merge",hint:'Provide: { merge: { verifications: [{key: "1a", evidence: "..."}] } }'},revert:{field:"revert",hint:'Provide: { revert: { reason: "..." } }'},search:{field:"search",hint:'Provide: { search: { query: "..." } }'}}[r]
5603
5626
  n&&!e[n.field]&&t.addIssue({code:"custom",message:`'${r}' operation requires '${n.field}' data. ${n.hint}`})})
5604
- const m=n.z.string({required_error:"Required. A quick edit either touches up an earlier request's result or stands on its own: pass that request id (req######) or the word 'new'."}).refine(e=>"new"===e||/^req\d{6}$/.test(e),{message:"Pass a request id like req000031, or 'new'."}).describe("The request whose result this edit adjusts (the user pointed at it), or 'new': the same rule as create_request's follows.")
5605
- exports.QuickWriteSchema=n.z.object({title:n.z.string().min(1,"Title is required"),description:n.z.string().min(1,"Description is required"),follows:m,path:n.z.string().optional(),documentId:d.optional(),content:n.z.union([n.z.string(),n.z.array(n.z.string())]),format:n.z.enum(["text","json"]).optional(),append:n.z.boolean().optional()}).transform(u).refine(h,{message:"path or documentId required"}),exports.QuickReplaceSchema=n.z.object({title:n.z.string().min(1,"Title is required"),description:n.z.string().min(1,"Description is required"),follows:m,operations:n.z.array(n.z.object({path:n.z.string().optional(),documentId:d.optional(),replacements:n.z.array(n.z.object({old_str:n.z.string().min(1),new_str:n.z.string(),match_mode:n.z.enum(["unique","all"]).optional()})).min(1),fuzzy_match:n.z.boolean().optional()}).transform(u).refine(h,{message:"path or documentId required"})).min(1),fuzzy_match:n.z.boolean().optional(),comment:n.z.string().min(1,"Comment describing the change is required")}),exports.MetaWorkflowListSchema=n.z.object({}),exports.MetaWorkflowGetSchema=n.z.object({workflowId:n.z.string().describe("Workflow ID to retrieve")}),exports.MetaWorkflowCreateSchema=n.z.object({name:n.z.string().min(1).describe("Unique name for the workflow"),shortName:n.z.string().min(1).max(10).describe("Short display name (required, max 10 chars)"),description:n.z.string().optional().describe("Description of what the workflow does"),testGate:n.z.enum(["off","auto","ask"]).optional().describe("Test gate: off (no test gate), auto (checks run automatically; a blocking command must pass, an advisory one may be skipped with a reason), ask (the user picks auto/interactive/skip at each completion)"),reviewGate:n.z.enum(["off","on"]).optional().describe("Review gate: off, or on (one reviewer checks each acceptance criterion, with the reviewers the kind assigns: guidance, model on engineering, any the workflow added)"),signoffGate:n.z.enum(["off","agent","you"]).optional().describe('Sign-off gate, as the workflow page names it: off; agent ("Delivery review": an agent asks whether the delivery is what was asked for, then merges or brings it to the user); you ("You sign off": the user approves before merge)'),approvalMode:n.z.enum(["none","require-approval","agent-check"]).optional().describe("Pre-work approval: none (default), require-approval (the user approves each request), or agent-check (an independent intake reviewer rules on agent-created requests before work starts)"),interactionPosture:n.z.enum(["autonomous","balanced","collaborative"]).optional().describe("Interaction posture (question-gate dial): autonomous (defaulted questions are self-answered -- proceed + FYI report), balanced (default; questions post normally, non-blocking when defaulted), collaborative (always ask the human)")}),exports.MetaWorkflowUpdateSchema=n.z.object({workflowId:n.z.string().describe("Workflow ID to update"),name:n.z.string().min(1).optional().describe("New name"),shortName:n.z.string().max(10).optional().describe("New short name (max 10 chars)"),description:n.z.string().optional().describe("New description"),testGate:n.z.enum(["off","auto","ask"]).optional().describe("Test gate: off (no test gate), auto (checks run automatically; a blocking command must pass, an advisory one may be skipped with a reason), ask (the user picks auto/interactive/skip at each completion)"),reviewGate:n.z.enum(["off","on"]).optional().describe("Review gate: off, or on (one reviewer checks each acceptance criterion, with the reviewers the kind assigns: guidance, model on engineering, any the workflow added)"),signoffGate:n.z.enum(["off","agent","you"]).optional().describe('Sign-off gate, as the workflow page names it: off; agent ("Delivery review": an agent asks whether the delivery is what was asked for, then merges or brings it to the user); you ("You sign off": the user approves before merge)'),approvalMode:n.z.enum(["none","require-approval","agent-check"]).optional().describe("Pre-work approval: none (default), require-approval (the user approves each request), or agent-check (an independent intake reviewer rules on agent-created requests before work starts)"),interactionPosture:n.z.enum(["autonomous","balanced","collaborative"]).optional().describe("Interaction posture (question-gate dial): autonomous (defaulted questions are self-answered -- proceed + FYI report), balanced (default; questions post normally, non-blocking when defaulted), collaborative (always ask the human)")}),exports.MetaRecipeListSchema=n.z.object({}),exports.MetaRecipeGetSchema=n.z.object({recipeId:n.z.string().describe("Recipe ID to retrieve")}),exports.MetaRecipeCreateSchema=n.z.object({name:n.z.string().min(1).describe("Unique name for the recipe"),description:n.z.string().optional().describe("Description of what the recipe does"),documentation:n.z.string().optional().describe("Detailed documentation")}),exports.MetaRecipeAddHookSchema=n.z.object({recipeId:n.z.string().describe("Recipe ID to add the hook to"),hookId:n.z.string().describe("Hook template ID to add"),position:n.z.number().int().min(0).optional().describe("Position in the recipe (0-based, appended if omitted)")}),exports.MetaRecipeRemoveHookSchema=n.z.object({recipeId:n.z.string().describe("Recipe ID to remove the hook from"),hookId:n.z.string().describe("Hook template ID to remove")}),exports.MetaHookListSchema=n.z.object({}),exports.MetaHookCreateSchema=n.z.object({name:n.z.string().min(1).describe("Unique name for the hook"),description:n.z.string().optional().describe("Description of what the hook does"),eventType:n.z.string().describe("Event type that triggers this hook (e.g., session_idle, request_completed, custom:plan_ready)"),category:n.z.enum(["alchemy","session","message","editing","reading","file_management","documents","history","tool"]).default("session").describe("Hook category"),agent:n.z.string().describe("Agent template to execute when hook fires"),promptTemplate:n.z.string().describe("Prompt template with {{variable}} substitution"),condition:n.z.record(n.z.any()).optional().describe("Condition object for filtering when hook fires"),timing:n.z.enum(["before","after"]).default("after").describe("When to fire relative to the event"),action:n.z.enum(["spawn_agent","inject_prompt"]).optional().describe("What the hook does: spawn_agent (default) starts a new session of `agent` with the prompt; inject_prompt sends the prompt into an existing session"),target:n.z.enum(["independent_session","child_session","same_session","parent_session","ancestor_chain"]).optional().describe("Where the prompt goes. With spawn_agent: independent_session (default, no parent) or child_session (under the session that fired the event). With inject_prompt: same_session (default, the session that fired the event), parent_session, or ancestor_chain"),maxIterations:n.z.number().int().min(1).optional().describe("Maximum times the hook fires for one session, counted from its firing record. Set it on every session_idle hook that sends into the same session. A session a hook started never triggers that hook again, whatever this says"),emitEvent:n.z.string().optional().describe("Custom event to emit on completion"),emitEventOnCondition:n.z.union([n.z.object({condition:n.z.object({field:n.z.string(),operator:n.z.enum(["contains","not_contains","equals","not_equals","matches","not_matches"]),value:n.z.string()}),event:n.z.string()}),n.z.array(n.z.object({condition:n.z.object({field:n.z.string(),operator:n.z.enum(["contains","not_contains","equals","not_equals","matches","not_matches"]),value:n.z.string()}),event:n.z.string()}))]).optional().describe("Conditional event emission based on output")}),exports.MetaWorkflowAddRecipeSchema=n.z.object({workflowId:n.z.string().describe("Workflow ID to add the recipe to"),recipeId:n.z.string().describe("Recipe ID to add"),position:n.z.number().int().min(0).optional().describe("Position in the workflow (0-based, appended if omitted)")}),exports.MetaWorkflowRemoveRecipeSchema=n.z.object({workflowId:n.z.string().describe("Workflow ID to remove the recipe from"),recipeId:n.z.string().describe("Recipe ID to remove")}),exports.MetaAgentListSchema=n.z.object({}),exports.MetaOperationsSchema=n.z.object({operation:n.z.enum(["workflow-list","workflow-get","workflow-create","workflow-update","recipe-list","recipe-get","recipe-create","recipe-add-hook","recipe-remove-hook","hook-list","hook-create","workflow-add-recipe","workflow-remove-recipe","agent-list"]).describe("Which meta operation to perform; the other params apply per operation (see tool description)"),...exports.MetaWorkflowGetSchema.partial().shape,...exports.MetaWorkflowCreateSchema.partial().shape,...exports.MetaWorkflowUpdateSchema.partial().shape,...exports.MetaRecipeGetSchema.partial().shape,...exports.MetaRecipeCreateSchema.partial().shape,...exports.MetaRecipeAddHookSchema.partial().shape,...exports.MetaRecipeRemoveHookSchema.partial().shape,...exports.MetaHookCreateSchema.partial().shape,...exports.MetaWorkflowAddRecipeSchema.partial().shape,...exports.MetaWorkflowRemoveRecipeSchema.partial().shape}),exports.TestingProcessListSchema=n.z.object({}),exports.TestingProcessGetSchema=n.z.object({processId:n.z.string().describe("Test process ID to retrieve")})
5606
- const g=n.z.object({name:n.z.string().min(1).describe('Command name (e.g., "Build", "Unit Tests")'),command:n.z.string().min(1).describe('Shell command to run (e.g., "npm test")'),required:n.z.boolean().default(!0).describe("If true, failure blocks the request (default: true)"),timeout:n.z.number().int().min(10).max(3600).default(300).describe("Max execution time in seconds (default: 300)")})
5607
- exports.TestingProcessCreateSchema=n.z.object({name:n.z.string().min(1).describe("Name for the test process"),environmentId:n.z.string().optional().describe("ID of the environment (confined runtime) this process runs in. Get it from environment_list or environment_setup."),description:n.z.string().optional().describe("Description of what this process verifies"),scope:n.z.string().optional().describe('LABEL ONLY -- a monorepo path prefix recorded for display (e.g. "packages/api/"). It does NOT affect when the process runs; use pathGlobs for that.'),pathGlobs:n.z.array(n.z.string()).optional().describe('Which changes this process runs on: glob patterns matched against the changed files (e.g. ["sites/**"], ["src/**", "*.md"]). THIS is what limits when the process runs. Omit it and the process runs on EVERY change, which is the right choice only for a check that is cheap and universal.'),areas:n.z.array(n.z.string()).optional().describe('Work-area labels this process covers (e.g. ["graphics/opengl"]). An alternative to pathGlobs for work that is not file-shaped; a process applies if EITHER dimension matches.'),setup:n.z.array(n.z.string()).optional().describe("Commands that prepare the tree for the tests (install the package itself, generate files the tests import), e.g. [\"python -m pip install --no-deps -e .\"]. They run in its box before its commands on every run, and also before a request's criteria checks, which run in a clean checkout of the commit where `commands` do not run: a preparation step put in `commands` is missing there and those checks fail. If one fails, the run fails as the environment's fault and the commands do not run."),commands:n.z.array(g).min(1).describe("Test commands to execute in order"),verifyAcceptanceCriteria:n.z.boolean().optional().describe("When true, auto-tester verifies request acceptance criteria after running commands"),fingerprint:n.z.array(n.z.string()).optional().describe('Files whose content invalidates setup. Setup commands re-run only when these files change between runs (e.g. ["package-lock.json"], ["Cargo.lock"], ["uv.lock", "poetry.lock"]). Polyglot repos list multiple. Omit / empty list = always re-run setup (existing behavior).'),poolSize:n.z.number().int().min(1).max(8).optional().describe("Number of warm test worktrees in the pool. Default 2. Set to 1 for languages with very large build artifacts (Rust target/, C++ build/). Higher values allow more parallel test runs at the cost of disk."),runtimeKept:n.z.string().optional().describe('Only when the user chose to run the check on a runtime other than the lowest one the project declares: that runtime and version, e.g. "python 3.12". Without it, a check whose environment runs another version than the declared minimum is not registered.'),leavesOut:n.z.array(n.z.object({what:n.z.string().describe('The left-out part in plain words, e.g. "the Valkey backend tests"'),paths:n.z.array(n.z.string()).min(1).describe('Globs for the code that part checks, so a change there goes unchecked by this check: for a backend\'s tests, that backend (e.g. ["aiocache/backends/valkey.py"]); for browser or end-to-end tests, the app source they drive (e.g. ["src/**"]). Not only the left-out test files.'),command:n.z.string().min(1).max(300).optional().describe('The command that runs that part, e.g. "pnpm test:e2e": a request whose criterion runs it is not told this part was left out.')})).optional().describe('What this check deliberately does not run and no other check runs (the suites the card lists as "not run on every change"), each with the code it checks. A change to that code is reported to the user as not checked by this check, unless the request ran that part itself.')}),exports.TestingProcessDeleteSchema=n.z.object({processId:n.z.string().describe("Test process ID to delete")}),exports.EnvironmentListSchema=n.z.object({}),exports.ResultsSchema=n.z.object({operation:n.z.enum(["record","fetch","pin","list","read"]),path:n.z.string().optional().describe("record: the file, inside the project (not /tmp); your worktree first, then the main project. Bulk that must not reach a commit can be written by a command under `.alchemy_lab/scratch/` (gitignored)."),name:n.z.string().optional().describe("record: the name a person uses for it (defaults to the filename). list: show every version recorded under this name, newest first."),summary:n.z.record(n.z.any()).optional().describe('record (required): the small facts a reader wants instead of the bytes, e.g. {maxStress: 412, unit: "MPa", converged: true}.'),box:n.z.string().optional().describe("An experiment handle (exp_...). fetch: put the bytes inside that sealed box under its /scratch (a box cannot see the host scratch; omit for host work, which is faster). record: the result lives inside that box and is streamed out and stored in one step (a box cannot write your worktree)."),mediaType:n.z.string().optional().describe("record: MIME type, when you know it."),inputs:n.z.array(n.z.string()).optional().describe("record: addresses of the results this one was made from (provenance)."),note:n.z.string().optional().describe("record: one line on how it was produced."),address:n.z.string().optional().describe("pin / read / fetch: the full 64-character address the record returned (a unique prefix works too)."),at:n.z.string().optional().describe("pin: the pointer path in your worktree (.result.json is added). fetch: where the bytes land, under AlchemyLab's scratch folder for the project on the host (the answer gives the full path) or the box's `/scratch`. Defaults to results/<name>."),comment:n.z.string().optional().describe("pin: the commit comment for the pointer file."),offset:n.z.number().optional().describe("read: line to start at (default 0)."),limit:n.z.number().optional().describe("read: how many lines (default 200). list: how many results (default 25)."),find:n.z.string().optional().describe("read: return only lines containing this text, instead of a range.")}),exports.ResultInspectSchema=n.z.object({operation:n.z.enum(["list","read"]),name:n.z.string().optional().describe("list: show every version recorded under this name, newest first."),address:n.z.string().optional().describe("read: the full 64-character address of the result, a check run's id (tr_...) or a command run's record id (trec...), to read what its commands printed."),offset:n.z.number().optional().describe("read: line to start at (default 0)."),limit:n.z.number().optional().describe("read: how many lines (default 200). list: how many results (default 25)."),find:n.z.string().optional().describe("read: return only lines containing this text, instead of a range.")}),exports.ExperimentStartSchema=n.z.object({env:n.z.string().optional().describe("Environment by name (from environment_list), one whose image has the toolchain you need."),environmentId:n.z.string().optional().describe("Environment by id (alternative to `env`). The primary env is used if neither is given."),size:n.z.enum(["light","standard","heavy"]).optional().describe("light: 2 cores (lint, a typecheck, one test file). standard (default): a share of the free cores (a suite, a build). heavy: every free core but 2 and 6 GB of memory (2 GB otherwise, unless the environment sets its own), for work that uses them (a CFD solve, meshing, a large parallel build, a model that runs out of memory). A size you do not hold opens another box."),confirmWorkspace:n.z.boolean().optional().describe('Required for env "workspace" (the live host): the task genuinely needs the real machine. Building or trying out the app does not.')}),exports.ExperimentStopSchema=n.z.object({handle:n.z.string().describe("The experiment handle to tear down.")}),exports.ExperimentListSchema=n.z.object({}),exports.ReadSiteSchema=n.z.object({url:n.z.string()}),exports.DriveSiteSchema=n.z.object({url:n.z.string().describe("The running product, e.g. the environment's published URL or http://localhost:5173."),steps:n.z.array(n.z.object({action:n.z.enum(["click","clickat","type","press","move","scroll","wait","media"]).describe('click (selector) \xb7 clickat (x,y) \xb7 type (selector + text) \xb7 press (key) \xb7 move (x,y) \xb7 scroll (dy) \xb7 wait (ms, max 5000) \xb7 media ("print" shows the printout, "screen" switches back)'),selector:n.z.string().optional().describe('Playwright selector, e.g. "text=Build" or "#start".'),text:n.z.string().optional(),key:n.z.string().optional().describe('e.g. "Enter"'),x:n.z.number().optional(),y:n.z.number().optional(),dy:n.z.number().optional(),ms:n.z.number().optional(),media:n.z.enum(["print","screen"]).optional()})).min(1).max(20),shots:n.z.enum(["each","final"]).optional().describe('"each" screenshots every step; default the final state only.'),session:n.z.string().optional().describe("Keeps the page open: the next call with this name continues where this one stopped. Idle sessions close after 10 minutes."),close:n.z.boolean().optional().describe("Close the named session after this call."),width:n.z.number().optional().describe("Viewport width for a new session (default 1280; 390 is a phone).")}),exports.CaptureSiteSchema=n.z.object({url:n.z.string(),fullPage:n.z.boolean().optional().describe("The whole scrollable page instead of the viewport."),width:n.z.number().optional().describe("Viewport width (default 1280; 390 is a phone).")}),exports.PreviewSiteSchema=n.z.object({dir:n.z.string().optional().describe('Repo-relative, e.g. "dist" or "." for the top of the repository. Not needed with stop.'),requestId:n.z.string().regex(/^req\d{6}$/).optional().describe("Serve from this unmerged request's working copy instead of main."),name:n.z.string().optional().describe("Preview handle (default: a slug of dir); reusing one replaces that preview. With stop: the preview to stop."),stop:n.z.boolean().optional().describe("Stop a running preview instead of serving one: the one named, or the only one running."),label:n.z.string().optional()}),exports.FetchAssetSchema=n.z.object({url:n.z.string().describe("The http(s) URL of the image or font to download."),destPath:n.z.string().describe('Where to write it, repo-relative (e.g. "sites/acme/assets/hero.jpg"). Must stay inside the working tree; parent directories are created.')}),exports.RequestVisualFeedbackSchema=n.z.object({box:n.z.string().optional().describe("The experiment handle (from experiment_start, on a screenshot-capable env) to render in / read from. The box must stay held until this returns."),route:n.z.string().optional().describe('With `box`: the route I render + screenshot FOR YOU (e.g. "/" or "/settings"). I serve `serveDir` and screenshot it -- you do NOT hand-roll serve/screenshot. This is the easiest path.'),script:n.z.string().optional().describe('With `box`, for FULL control: a Playwright snippet (the body of `async (page, baseUrl) => { ... }`). I serve the app, launch headless Chromium, and run your script -- navigate (page.goto(baseUrl + "/x")), click, fill, scroll, waitForSelector, etc. -- then screenshot the final page state. Reliable: you write only the interaction, no serve/launch/flags. Use this to reach a state that needs interaction (open a menu, log in, submit a form).'),fullPage:n.z.boolean().optional().describe("Capture the entire scrollable page instead of just the viewport."),serveDir:n.z.string().optional().describe("With `box`+`route`: the static dir to serve (default /work). For a built app, build first via run(), then point this at the build output (e.g. /work/dist)."),path:n.z.string().optional().describe("Alternative to route: a screenshot you ALREADY wrote inside the box (e.g. /tmp/shot.png); I read it out."),assetFilename:n.z.string().optional().describe("Alternative to box: the filename of an already-uploaded screenshot asset to annotate."),prompt:n.z.string().optional().describe("What you want the human to look at or mark up (shown with the request)."),timeoutMs:n.z.number().optional().describe("How long to wait for the human, in ms (default ~10 min).")}),exports.AskUserVisualSchema=n.z.object({question:n.z.string().describe('The question for the USER about the marked region (e.g. "Should this button use the primary color?").'),imagePath:n.z.string().optional().describe("Repo-relative path to an image you already produced (png/jpg/gif/webp), e.g. a screenshot you wrote. Provide this OR previewName."),previewName:n.z.string().optional().describe("Name of a registered live preview (a `live:` ref); I freeze it into a snapshot image for you. Provide this OR imagePath."),box:n.z.string().optional().describe('The region the question is about: "x,y,w,h" in normalized 0..1 image coordinates, origin top-left (e.g. "0.62,0.08,0.3,0.12"). Omit to ask about the whole image.'),options:n.z.array(n.z.string()).optional().describe("Optional answer choices (labels). Omit for a free-text answer."),context:n.z.string().optional().describe("Extra context shown with the question in the inbox (why you are asking, what you will do with the answer)."),priority:n.z.enum(["low","normal","high"]).optional().describe('Question priority; "high" always reaches the user regardless of autonomy dial.')}),exports.EnvironmentGetSchema=n.z.object({environmentId:n.z.string().describe("Environment ID to retrieve")}),exports.EnvironmentProvisionSchema=n.z.object({environmentId:n.z.string(),why:n.z.string().optional().describe("Why provision now (shown on the approval).")}),exports.EnvironmentTeardownSchema=n.z.object({environmentId:n.z.string()}),exports.EnvironmentStatusSchema=n.z.object({environmentId:n.z.string()}),exports.EnvironmentVerifyStackSchema=n.z.object({environmentId:n.z.string()})
5608
- const y=n.z.object({image:n.z.string().optional().describe("Container image carrying the project toolchain/deps, e.g. node:20-alpine, python:3.12-slim, golang:1.22, ruby:3.3"),install:n.z.string().optional().describe("Deps install command -- Node-only sugar that populates a /work/node_modules cache volume, run with registry egress before the confined gate, e.g. npm ci. Non-Node runtimes use `artifacts` instead (a cache volume + prepare command: .venv/uv sync, cargo, go, vendor/bundle). Omit if the project has no deps."),composeFile:n.z.string().optional().describe("Path to the project docker-compose file for its services. Omit if no services."),shellInit:n.z.string().optional().describe("Shell preamble run before EVERY command in the box, e.g. '. /usr/lib/openfoam/openfoam2312/etc/bashrc'. REQUIRED for a toolchain that publishes itself through a script rather than the image PATH (OpenFOAM etc/bashrc, oneAPI setvars.sh, conda activate, ROS setup.bash): `docker exec` runs no ENTRYPOINT and reads no login profile, so without this every command gets a bare PATH. Put the preamble HERE, never inside the smoke command -- a smoke command carrying its own preamble proves the preamble and not the environment, and the next agent gets nothing."),connEnv:n.z.record(n.z.string()).optional().describe("Connection env injected into the gate (e.g. DATABASE_URL) using SERVICE NAMES + internal ports, never localhost/host ports."),seed:n.z.array(n.z.string()).optional().describe("Optional commands run after services are up (e.g. migrations)."),artifacts:n.z.array(n.z.object({path:n.z.string().describe("Mount target for the writable, populated volume: relative to /work for a dependency folder the project's toolchain looks for there (node_modules, .venv, vendor/bundle), or absolute (e.g. /cache/cargo). Tools you install (apt/apk packages, binaries) go at an absolute path outside /work, such as /tools: /work is the project's folder, and its test runners see anything in it."),prepare:n.z.string().optional().describe("Command that populates it -- the one phase with registry egress (e.g. npm ci, uv sync, cargo fetch). Omit for a writable empty volume."),manifests:n.z.array(n.z.string()).optional().describe("Lockfiles (relative to /work) whose content hash keys the cache; list them so the volume is reused across runs and only rebuilt when deps change (e.g. uv.lock, Cargo.lock). Omit => rebuilt every run."),env:n.z.record(n.z.string()).optional().describe('Env applied during prepare AND every run, e.g. { CARGO_HOME: "/cache/cargo" } for caches outside /work.')})).optional().describe("Per-runtime build/dependency artifacts: writable volumes populated by a prepare command, generalizing `install` beyond node_modules. Use for Python (.venv), Rust (target + $CARGO_HOME), Go, Ruby (vendor/bundle), etc. `install` is sugar for a single node_modules artifact; for any non-Node runtime use artifacts (install would write to node_modules, the wrong place)."),confinement:n.z.enum(["confined","egress-allowlist","privileged","unsafe","host","pure-host"]).optional().describe("Confinement level. Default 'confined' (fully sealed Docker; add egressAllowlist hosts to open exactly those -- stored as 'egress-allowlist'). privileged/unsafe relax the container. 'host' runs on the host machine (no Docker) inside an OS sandbox (Seatbelt/bubblewrap) for toolchains Docker can't run. 'pure-host' is the built-in workspace env (the live worktree) -- do not create new envs with it. Merge gating is independent (the Sign-off setting)."),commandGate:n.z.array(n.z.enum(["policy","agent","human"])).optional().describe("Gates an experiment command passes before it runs, in escalation order policy -> agent -> human. Empty = run freely; escalating past the last gate blocks (fail closed). policy = deterministic allowlist/deny-floor; agent = isolated LLM judge (allow or escalate only); human = ask. Registered commands are pre-approved. Defaults by level ([] for confined/egress-allowlist, ['human'] for privileged/unsafe)."),worktreeTarget:n.z.enum(["ephemeral","live"]).optional().describe("Worktree the env runs against: 'ephemeral' (a disposable copy at HEAD, default) or 'live' (the project's live working dir, read-write). The built-in workspace env is 'live'."),egressAllowlist:n.z.array(n.z.string()).optional().describe("Hosts the box may reach at the 'egress-allowlist' level (exact name or subdomain, e.g. registry.npmjs.org). Ignored at other levels."),addCaps:n.z.array(n.z.string()).optional().describe("Linux capabilities to add at the 'privileged' level (on top of cap-drop ALL), e.g. SYS_PTRACE for debuggers, IPC_LOCK for memlock. Ignored at other levels."),sysctls:n.z.record(n.z.string()).optional().describe("Namespaced sysctls to set at the 'privileged' level, e.g. net.ipv4.ip_local_port_range. Host-wide sysctls (vm.max_map_count) are NOT settable per-container."),runAsRoot:n.z.boolean().optional().describe("Run the box as root (privileged / unsafe levels). Needed for some caps + the docker socket."),dockerSocket:n.z.boolean().optional().describe("Mount the host docker socket for testcontainers-style tests. WARNING: full host control over the docker daemon. Only honored at the 'unsafe' level."),persistentVolumes:n.z.array(n.z.object({name:n.z.string(),target:n.z.string(),service:n.z.string().optional()})).optional().describe("Data volumes that survive between runs (keyed to this environment; off by default since experiments are ephemeral). Set service to mount into a compose service (e.g. a DB data dir), or omit it to mount into the box (e.g. a SQLite dir)."),resources:n.z.object({memory:n.z.string().optional().describe("Memory cap for this environment's boxes and its checks' boxes, e.g. '4g' (default 2g; 6g at size heavy). Set it when the test suite or build needs more."),cpus:n.z.number().optional().describe("A fixed CPU count. Usually leave it unset and set size instead."),size:n.z.enum(["light","standard","heavy"]).optional().describe("What this environment's boxes and checks are for, which sets their cores from what is free: light (2 cores: lint, small checks), standard (the default: a share of the free cores, for test suites and builds), heavy (every free core but 2: CFD or FEM solves, meshing, large parallel builds). An agent can ask for another size per box."),pidsLimit:n.z.number().optional().describe("Max processes (default 512)."),scratchMb:n.z.number().optional().describe("Size in MB of an in-memory /scratch, used only when the image cannot take the disk-backed one (default 512). /scratch is normally on disk and needs no size."),shmMb:n.z.number().optional().describe("/dev/shm size in MB -- bump for headless browsers (Chrome crashes on the 64m default).")}).optional().describe("Per-environment resource caps that override the confined defaults.")}),w=r(y),b='Start from a built-in preset; anything in config overrides it. "office": python-docx, openpyxl, python-pptx, pandoc, LibreOffice and segno/zbarimg (QR codes) in a sealed box, with `render-pdf FILE` to turn Word, Excel, PowerPoint, Markdown or HTML into PDF. Its image is built locally on first use (a few minutes). Pass the same preset (and config) to environment_verify and environment_create.',v="Save without a passing environment_verify, only for a config that cannot be verified from here (it needs credentials, external services or hardware the confined verifier lacks). Requires skipVerifyReason; the skip is logged."
5609
- exports.EnvironmentCreateSchema=n.z.object({name:n.z.string().min(1).describe("Name for the environment, e.g. node + postgres"),description:n.z.string().optional().describe("What this environment provides"),scope:n.z.string().optional().describe("Subproject path prefix for monorepos (e.g. packages/api/). Omit for the whole repo."),preset:n.z.enum(["office"]).optional().describe(b),config:w.optional().describe("The exact config (after the preset) that passed environment_verify in this session, unless skipVerify; its fields are described on environment_verify. Optional with a preset."),isPrimary:n.z.boolean().optional().describe("Make this the project primary environment (default for new test processes). The first environment is primary automatically."),skipVerify:n.z.boolean().optional().describe(v),skipVerifyReason:n.z.string().optional().describe("Why this config cannot be verified (required with skipVerify: true; recorded in the log).")}),exports.EnvironmentUpdateSchema=n.z.object({environmentId:n.z.string(),name:n.z.string().min(1).optional(),description:n.z.string().optional(),scope:n.z.string().optional(),config:w.optional().describe("Replaces the config wholesale: the exact config that passed environment_verify in this session, unless skipVerify (fields described on environment_verify). Metadata-only updates need no verify."),isPrimary:n.z.boolean().optional().describe("Make this the project primary environment"),skipVerify:n.z.boolean().optional().describe(v),skipVerifyReason:n.z.string().optional().describe("Why this config cannot be verified (required with skipVerify: true; recorded in the log).")}),exports.EnvironmentDeleteSchema=n.z.object({environmentId:n.z.string().describe("Environment ID to delete")}),exports.EnvironmentVerifySchema=n.z.object({preset:n.z.enum(["office"]).optional().describe(b),config:y.optional().describe("The proposed environment config to verify (image, install, services, connection). Optional with a preset."),smoke:n.z.string().optional().describe("Optional smoke command run confined after the environment is up (default: true). Use a connection probe to confirm services are reachable.")}),exports.EnvironmentSetupSchema=n.z.object({name:n.z.string().max(60).optional().describe("A few words naming what you need (e.g. 'Node 20 for syntax checks')."),context:n.z.string().optional().describe("What you need and why, for the setup architect (e.g. 'Node 20 to run node --check on standalone .js files; no deps').")}),exports.SetupFinishSchema=n.z.object({outcome:n.z.enum(["ready","declined","could_not_finish","no_code","not_yet"]).describe("How the run ended. 'ready' needs something saved in this run."),summary:n.z.string().min(1).describe("What was set up (names and ids), and an answer to every ask the run carries: done, or not done and why. Plain words; it reaches the waiting workers and the user."),startsAfter:n.z.string().regex(/^req\d{6}$/).optional().describe("With 'not_yet': the request still writing what this setup registers.")}),exports.TestingProcessUpdateSchema=n.z.object({processId:n.z.string(),environmentId:n.z.string().optional(),name:n.z.string().min(1).optional(),description:n.z.string().optional(),scope:n.z.string().optional().describe("A display label only; pathGlobs decides when the process runs."),pathGlobs:n.z.array(n.z.string()).optional().describe('Globs matched against changed files (e.g. ["src/**", "*.md"]): the changes this process runs on. Replaces the list; [] means every change.'),areas:n.z.array(n.z.string()).optional().describe("Work-area labels this process covers; it applies when pathGlobs or areas match."),isActive:n.z.boolean().optional(),setup:n.z.array(n.z.string()).optional().describe("Replaces the setup commands (run in the check's box before its commands, and before the criteria checks in their clean checkout)."),commands:n.z.array(g).optional().describe("Replaces the test commands."),verifyAcceptanceCriteria:n.z.boolean().optional().describe("The auto-tester also verifies the request's acceptance criteria."),fingerprint:n.z.array(n.z.string()).optional().describe("Files whose content invalidates setup."),leavesOut:n.z.array(n.z.object({what:n.z.string().describe('The left-out part in plain words, e.g. "the Valkey backend tests"'),paths:n.z.array(n.z.string()).min(1).describe("Globs for the code that part checks (for end-to-end tests, the app source they drive), not only its test files."),command:n.z.string().min(1).max(300).optional().describe('The command that runs that part, e.g. "pnpm test:e2e".')})).optional().describe("Replaces what this check deliberately does not run, with the code each part checks; [] clears it."),poolSize:n.z.number().int().min(1).max(8).optional().describe("Warm test worktrees in the pool."),runtimeKept:n.z.string().optional().describe('With environmentId: only when the user chose a runtime other than the lowest one the project declares, e.g. "python 3.12".')}),exports.TestsSchema=n.z.object({operation:n.z.enum(["list","setup","run","switch-off","switch-on"]),process:n.z.string().optional().describe("run, switch-off, switch-on: one test process by name or id (run: omit for all active ones)."),userSaid:n.z.string().max(600).optional().describe("switch-off / switch-on: the user's words asking for it, copied exactly."),name:n.z.string().optional().describe("run: one test command by name; omit for all required commands."),ask:n.z.string().max(1500).optional().describe("setup, required outside a request: what the user asked the check to run, in their words; the setup architect registers exactly that.")}),exports.ExecuteTestCommandSchema=n.z.object({processId:n.z.string().describe("Test process ID containing the command"),commandName:n.z.string().describe('Name of the test command to run, or "setup" to run all setup commands in sequence')}),exports.RunSchema=n.z.object({command:n.z.string().optional().describe("A shell command, run in the box (pass box or env)."),name:n.z.string().optional().describe("A saved command by name, instead of command."),box:n.z.string().optional().describe("An experiment handle from experiment_start."),env:n.z.string().optional().describe("Instead of box: an environment by name; its box is started (or your open one reused) and the result gives the handle."),size:n.z.enum(["light","standard","heavy"]).optional().describe("With env: the box size (see experiment_start)."),args:n.z.string().optional(),grep:n.z.string().optional().describe("Filter output through grep -i with this pattern."),timeout:n.z.number().optional().describe("Seconds."),why:n.z.string().optional().describe("One short sentence, shown on the approval card when the command needs the user's approval."),cwd:n.z.string().optional().describe('A subdirectory for an ad-hoc command (e.g. "apps/web"); a command starting with `cd` is refused in favour of this.')}),exports.CommandsSchema=n.z.object({operation:n.z.enum(["run","list","remove","register","setup"]).default("run").describe('list, setup, register or remove ("run" is the run tool\'s job).'),name:n.z.string().optional().describe("remove: the command name."),args:n.z.string().optional(),grep:n.z.string().optional(),command:n.z.string().optional(),timeout:n.z.number().optional(),cwd:n.z.string().optional(),context:n.z.string().optional().describe("setup: the command wanted, where it runs and what it is for."),commands:n.z.array(n.z.object({name:n.z.string().min(1).describe('e.g. "test:web"'),command:n.z.string().min(1),description:n.z.string().min(1).describe("What this command verifies."),cwd:n.z.string().optional().describe("Relative to the project root (monorepo subdirs); omit for the root."),timeout:n.z.number().optional().describe("Seconds (default 60)."),environment:n.z.string().optional().describe('The environment it runs in, by name (environment_list). Omitted, it goes where you ran it (a bare box with no saved environment is refused, so name one). Name "Workspace" only when it truly needs the host.'),target:n.z.string().optional().describe("The id your setup instructions give for a target this command prints the number for.")})).optional().describe("register: the commands to register.")}),exports.ReportTestResultsSchema=n.z.object({status:n.z.enum(["passed","failed","error"]).describe("Overall result"),testRunId:n.z.string().optional().describe("The test run this verdict belongs to (given in your instructions). Strongly preferred: without it the latest run is guessed, which misattributes results when several testers run concurrently."),results:n.z.object({commands:n.z.array(n.z.object({name:n.z.string().describe("Command name"),status:n.z.enum(["passed","failed","skipped","error"]).describe("Command result"),output:n.z.string().optional().describe("Relevant output snippet"),diagnosis:n.z.string().optional().describe("Why it failed, if applicable")})).describe("Per-command results"),summary:n.z.string().describe("Brief overall summary"),acceptanceCriteria:n.z.array(n.z.object({criterion:n.z.string().describe("The acceptance criterion text"),status:n.z.enum(["verified","unverified","unclear"]),evidence:n.z.string().describe("How verified, or why not")})).optional().describe("AC verification results, if applicable"),faultClass:n.z.enum(["fail_code","fail_evidence","fail_environment","fail_process"]).optional().describe("On a FAILED verdict, WHY it failed so the gate routes to the right actor: 'fail_code' (the change is wrong), 'fail_evidence' (the run did not prove a criterion the coder could have proven: attach/adjust verify commands), or 'fail_environment' (a required tool/runtime is MISSING from the confined box, e.g. 'node: not found': the coder cannot fix this; the environment must be extended). Use 'fail_environment' ONLY when the evidence shows a command/runtime absent from the box, never for a genuine defect or a fixable evidence gap. 'fail_process' is for a test process whose OWN command names a file the repository does not have (a deleted script): nobody's code is wrong and extending the box cannot help; the process itself must be fixed or turned off."),missingCapabilities:n.z.array(n.z.string()).optional().describe("With faultClass 'fail_environment', the binaries/runtimes the box lacks (e.g. ['node']) so the environment can be extended to provide them.")}).describe("Structured test results")}).superRefine((e,t)=>{"fail_environment"!==e.results?.faultClass||e.results.missingCapabilities&&e.results.missingCapabilities.length>0||t.addIssue({code:n.z.ZodIssueCode.custom,path:["results","missingCapabilities"],message:"faultClass 'fail_environment' requires results.missingCapabilities: name the absent binaries/runtimes (the deterministic capability probe in your evidence lists them, e.g. ABSENT from the box: node). Without the names, the environment cannot be extended and the request strands."})})
5610
- const k=n.z.string().min(1,"every option needs its consequence (description)").max(200,"an option's description is its consequence in one line: 200 characters at most").describe("Its consequence in one line: what it gets and costs."),I=n.z.string().min(1).max(120,"because is one clause: 120 characters at most")
5611
- exports.OpeningBriefSectionSchema=n.z.object({id:n.z.string().min(1).describe('Unique within the brief ("date-format").'),question:n.z.string().min(1).describe("The choice, one plain question answerable without your session."),context:n.z.string().min(1).describe("What it shapes, citing the request and its sources as stated; where they answer it, recommend their answer."),options:n.z.array(n.z.object({id:n.z.string().min(1),label:n.z.string().min(1),description:k})).min(2).describe("At least two genuine alternatives."),default:n.z.string().min(1).describe("The option you proceed on now (shown recommended)."),because:I.describe("Why, in one clause."),criteria:n.z.array(n.z.string().min(1)).optional().describe("Keys of criteria whose wording this choice decides (worded for your default); another pick marks them for rewording.")}).superRefine((e,t)=>{e.options.some(t=>t.id===e.default)||t.addIssue({code:n.z.ZodIssueCode.custom,path:["default"],message:`default '${e.default}' names no option in this section (option ids: ${e.options.map(e=>e.id).join(", ")})`}),"testing-mode"===e.id&&t.addIssue({code:n.z.ZodIssueCode.custom,path:["id"],message:"section id 'testing-mode' is reserved: the server composes the testing section when the project's gate needs it -- remove it from your sections"})}),exports.SessionMessageOperationsSchema=n.z.object({operation:n.z.enum(["send","note","reply","list","get","offer-handoff","record-decision","brief","withdraw"]),milestone:n.z.boolean().optional().describe("note: a real boundary (it works, the approach changed, the goal is met); one quiet line in the user's stream, a few per request at most."),percent:n.z.number().min(0).max(100).optional().describe("note: how far along your work on this request is; it may go down."),withdrawReason:n.z.string().optional().describe("withdraw: why the answer is no longer needed."),type:n.z.enum(["question","report"]).optional().describe("Required for send."),toSessionId:n.z.string().optional().describe('A session id, or "parent". Omit for the user (a broadcast).'),questionType:n.z.enum(["free-form","alternatives"]).optional().describe("Required for a question."),questionContent:n.z.object({question:n.z.string().min(1).describe("As the user reads it; a criterion by its words, never its key."),context:n.z.preprocess(e=>null!==e&&"object"==typeof e?JSON.stringify(e):e,n.z.string().optional()).optional().describe("What the user needs to answer without your session: what you found and why it matters. No paths or identifiers; output they should judge goes in a fenced block, as printed."),options:n.z.array(n.z.object({id:n.z.string(),label:n.z.string(),description:k,recommended:n.z.boolean().optional().describe("Your advice, highlighted (what happens unanswered is defaultOption). Not with criteria. Never on an option that makes up what the user has not given (estimates, sample values, invented names): leave it visibly empty or marked unknown."),because:n.z.preprocess(i,I.optional()).describe("With recommended (required there): why, in one clause."),notePrompt:n.z.string().min(3).max(120).optional().describe('For an option only useful with the user\'s words ("I want changes"): the question its text field asks ("What should change?"); the pick arrives with what they typed.'),effect:n.z.enum(["choose","send-back","not-yet"]).optional().describe('"choose" (default): records the pick. "send-back": asks for a change; on a request awaiting sign-off the pick itself sends it back (no reopen). "not-yet": [user-input] criteria only; they stay owed.')})).optional().describe("Genuine alternatives, each complete in one tap; recommended first. When the user's way cannot work, include one reaching their goal another way."),allowMultiple:n.z.boolean().optional(),fields:n.z.array(n.z.object({id:n.z.string().min(1),label:n.z.string().min(1),placeholder:n.z.string().optional()})).min(1).optional().describe('free-form: one labelled input per value; answers arrive as "Label: value" lines. Never ask for passwords or keys: answers are on the record.'),defaultOption:n.z.string().optional().describe("What happens if nobody answers before expiry (option id, or text for free-form); the asker resumes. It happens without the user, so it is the SAFE option when options differ in risk (silent value changes, data loss, made-up data, anything hard to undo), even if you recommend another; the context says so."),onExpiry:n.z.enum(["assume-default","escalate"]).optional().describe('"assume-default" (default with a defaultOption) or "escalate": stays pending for the user (on Self-driving only priority "high" reaches them).'),steer:n.z.enum(["what","how"]).optional().describe('"what" shapes the product (spec, wording, UX, scope); "how" the process (testing, sequencing), mostly yours to decide, not ask.'),changeableLater:n.z.boolean().optional().describe("true when the answer can change later without loss (nothing sent, deleted or published on it).")}).superRefine((e,t)=>{(e.options??[]).forEach((e,r)=>{!0!==e.recommended||e.because||t.addIssue({code:n.z.ZodIssueCode.custom,path:["options",r,"because"],message:`option '${e.id}' is recommended: say why in one clause (because)`})})}).optional().describe("Required for a question. Before asking the user: when context answers it and a wrong guess is cheap to fix, proceed. Otherwise ask with a defaultOption unless only the user can answer. Under 'autonomous' the default returns at once; 'balanced' holds up to ten minutes, then continues; 'collaborative' holds briefly, then ends your turn to wait. One decision per question, related uncertainties bundled; several candidate next steps are one alternatives question. A question the user already decided returns their decision: proceed on it."),priority:n.z.enum(["low","normal","high"]).optional().describe('"high": blocked with real stakes; reaches the user at once. "low" with a defaultOption: under \'balanced\', batched to the next checkpoint without holding.'),expiresInHours:n.z.number().optional(),userSaid:n.z.string().min(8).max(600).optional().describe('question: when the user asked to be asked ("ask me first"), their words exactly (checked); it then reaches them at any Autonomy.'),replaces:n.z.array(n.z.string().regex(/^Q-[A-Za-z0-9]+-\d+$/)).max(10).optional().describe("question: your open questions on the request this supersedes (they close). With one open, pass this or keepsOpen."),keepsOpen:n.z.boolean().optional().describe("question: it asks something else; your open ones stay open."),forceAsk:n.z.boolean().optional().describe("question: re-ask what the decision record answers, only because circumstances changed (say what in context)."),status:n.z.enum(["success","partial","failure","blocked"]).optional().describe("report: how it ended. Omitted reads success, or blocked with blockedOn."),blockedOn:n.z.string().optional().describe('Required with status "blocked" on your request: "decision" (the user\'s open card on it, else a question to your parent), a card code ("Q-AB12CD34-001"), or a request id (a wait; you are told when it settles).'),criteria:n.z.array(n.z.string().min(1)).max(10).optional().describe('question: keys of the [user-input] criteria you ask for; only this counts as asking them. No default, no recommended option; the answer is their proof unless it is "not-yet". With a "not-yet" option you build on a placeholder meanwhile (Self-driving answers it at once); without one you wait at every Autonomy. Their check of finished work is asked on the end card, not here.'),attention:n.z.enum(["fyi","glance","act"]).optional().describe("'fyi' (no badge), 'glance', 'act'. Default from status: failure/blocked act, partial glance, success fyi."),reportKind:n.z.enum(["milestone","reply"]).optional().describe("'reply': answers the user's inbox message."),summary:n.z.string().optional().describe("Required for a report: outcome first, subject named first (it shows alone, often hours later), paths in details."),details:n.z.string().optional().describe("With blockedOn \"decision\", the question's context (maybe the user's card): plain words, no tool names; explain a refusal, never paste it."),ruleVerdicts:n.z.array(n.z.object({rule:n.z.string().min(1).max(80).describe("The guidance id, no brackets."),verdict:n.z.enum(["held","broken","not_applicable"]),note:n.z.string().max(300).optional().describe("broken: what and where (file:line).")})).max(40).optional().describe("report, Guidance reviewer: a verdict on every item you were given."),silent:n.z.boolean().optional().describe("Record without waking the coordinator (fan-out research)."),relatesTo:n.z.string().regex(/^[IQ]-[A-Za-z0-9]+-\d+$/,"relatesTo must be an instruction code (I-...) or question code (Q-...)").optional().describe("An instruction code (I-...); for record-decision, the question (Q-...) it resolves."),decision:n.z.string().optional().describe("record-decision (required): the one-line call."),why:n.z.string().optional().describe("record-decision: the reasoning."),context:n.z.string().optional().describe("record-decision: what the choice was about."),requestId:n.z.string().optional().describe("The request it is about, so it shows there (note: defaults to yours; brief: required); without it a report or decision is filed at the project."),area:n.z.string().optional().describe("record-decision: a work area the call is about (without requestId)."),sections:n.z.array(exports.OpeningBriefSectionSchema).min(1).optional().describe("brief (required): your real design choices."),messageCode:n.z.string().optional().describe("Required for reply, get and withdraw."),amount:n.z.number().positive().max(1e5).optional().describe("Dollars the user named, their words in quote: 'build' on a Plan ready card sets the plan's budget; 'allow' on a budget card allows that much more."),sectionAnswers:n.z.record(n.z.string(),n.z.string().nullable()).optional().describe("reply to an opening brief: { sectionId: optionId } for sections the user answered, changed or confirmed, with quote; null when one no longer applies; 'your-words' when no option says what they asked. Unnamed sections stay open; a change sends finished work back to rework."),quote:n.z.string().optional().describe("reply: the user's words this answer records, exactly (refused if they never wrote them); omit for your own decision. Options that are the user's own statement (\"I checked, it works\") only they can pick."),text:n.z.string().optional().describe("reply: a free-form answer. note (required): the note."),selectedOptions:n.z.array(n.z.string()).optional().describe("reply: the picked option ids."),notes:n.z.string().optional(),escalate:n.z.boolean().optional().describe("reply to a question to you that needs the user: a copy reaches them with your recommendation (notes); the asker gets their answer. Not for broadcasts."),list:n.z.object({sessionId:n.z.string().optional().describe("Defaults to your session."),messageType:n.z.enum(["question","report","instruction","all"]).default("all"),direction:n.z.enum(["incoming","outgoing","all"]).default("all"),status:n.z.enum(["pending","answered","expired","success","partial","failure","blocked","all"]).default("all"),readStatus:n.z.enum(["unread","read","acknowledged","all"]).default("all"),requestId:n.z.string().optional().describe("Only messages about this request."),limit:n.z.number().min(1).max(100).default(50),offset:n.z.number().min(0).default(0)}).optional(),offerHandoff:n.z.object({summary:n.z.string().describe("One sentence: what the plan builds."),requestIds:n.z.array(n.z.string()).describe("Requests created from the plan.")}).optional()}).refine(e=>"send"===e.operation?!!e.type:"note"===e.operation?"string"==typeof e.text&&e.text.trim().length>0:"reply"===e.operation?!!e.messageCode:"list"===e.operation||("get"===e.operation?!!e.messageCode:"offer-handoff"===e.operation||("record-decision"===e.operation?!!e.decision:"brief"===e.operation?!!e.requestId&&Array.isArray(e.sections)&&e.sections.length>0:"withdraw"===e.operation&&!!e.messageCode)),{message:"Invalid operation data: send requires type, note requires text, reply requires messageCode, get requires messageCode, record-decision requires decision, brief requires requestId and a non-empty sections array, withdraw requires messageCode"}),exports.CommitToViewedSessionSchema=n.z.object({message:n.z.coerce.string().min(1).describe("The cleaned-up user message to post to the viewed session. Fix obvious dictation errors, add punctuation, but preserve the user's intent exactly.")}),exports.DirectiveOperationsSchema=n.z.object({operation:n.z.enum(["set","list","search-decisions"]).describe("search-decisions = free-text search the project's decision + annotation record"),targetType:n.z.enum(["project","area","request","you"]).optional(),targetId:n.z.string().optional(),body:n.z.string().max(2e3).optional(),note:n.z.string().optional(),userSaid:n.z.string().optional(),revises:n.z.string().max(160).optional(),status:n.z.string().optional(),query:n.z.string().max(200).optional().describe("search-decisions: the search text, matched against recorded decisions (question + answer) and annotations (comment body + quoted text). Required for search-decisions."),limit:n.z.number().int().min(1).max(50).optional().describe("search-decisions: max matches per record type (default 10).")}),exports.McpConnectionsSchema=n.z.object({operation:n.z.enum(["list","propose"]).describe("list = the connections this project has; propose = register one, switched off, for the user to switch on."),name:n.z.string().optional().describe("propose: the connection name, lower case letters, digits and dashes. It becomes the tool prefix (name_tool)."),transport:n.z.enum(["repo","boxed","remote"]).optional().describe("propose: repo = a server in THIS repository, built from its Dockerfile and run in a confined box (the repository is mounted read-only at /work, /scratch is writable memory, the image ENTRYPOINT is what runs, rebuilt when its files change on main); boxed = a published npm package at an exact version, installed once and run in a box; remote = a hosted server reached by url."),dockerfile:n.z.string().optional().describe("propose repo: path of the Dockerfile inside the repository, e.g. mcp/server.Dockerfile."),context:n.z.string().optional().describe("propose repo: the docker build context directory inside the repository (default: the repository root)."),package:n.z.string().optional().describe("propose boxed: npm package with an exact version, e.g. @scope/server@1.2.3."),bin:n.z.string().optional().describe("propose boxed: the bin to run, the name under node_modules/.bin."),url:n.z.string().optional().describe("propose remote: the http(s) url."),environment:n.z.record(n.z.string()).optional().describe("propose: plain KEY=value configuration (headers for remote). Never put a secret here; name it in secretKeys instead."),secretKeys:n.z.array(n.z.string()).optional().describe("propose: names of environment variables (or headers) whose VALUES are secret. The user sets the values on the machine that runs the work; they never reach the database.")}),exports.AnswerQuestionSchema=n.z.object({messageCode:n.z.string().min(1).describe("The code in square brackets from <waiting_on_you>, e.g. Q-51209THD-005."),optionId:n.z.string().optional().describe("The id of the option the user picked, when the question has options."),text:n.z.string().optional().describe("The user's answer in their own words, cleaned up, when the question has no options or they said something the options do not cover.")})},19567(e,exports,t){exports.Server=exports.SSEServerTransport=exports.StdioServerTransport=void 0
5627
+ const g=o.z.string({required_error:"Required. A quick edit either touches up an earlier request's result or stands on its own: pass that request id (req######) or the word 'new'."}).refine(e=>"new"===e||/^req\d{6}$/.test(e),{message:"Pass a request id like req000031, or 'new'."}).describe("The request whose result this edit adjusts (the user pointed at it), or 'new': the same rule as create_request's follows.")
5628
+ exports.QuickWriteSchema=o.z.object({title:o.z.string().min(1,"Title is required"),description:o.z.string().min(1,"Description is required"),follows:g,path:o.z.string().optional(),documentId:u.optional(),content:o.z.union([o.z.string(),o.z.array(o.z.string())]),format:o.z.enum(["text","json"]).optional(),append:o.z.boolean().optional()}).transform(h).refine(p,{message:"path or documentId required"}),exports.QuickReplaceSchema=o.z.object({title:o.z.string().min(1,"Title is required"),description:o.z.string().min(1,"Description is required"),follows:g,operations:o.z.array(o.z.object({path:o.z.string().optional(),documentId:u.optional(),replacements:o.z.array(o.z.object({old_str:o.z.string().min(1),new_str:o.z.string(),match_mode:o.z.enum(["unique","all"]).optional()})).min(1),fuzzy_match:o.z.boolean().optional()}).transform(h).refine(p,{message:"path or documentId required"})).min(1),fuzzy_match:o.z.boolean().optional(),comment:o.z.string().min(1,"Comment describing the change is required")}),exports.MetaWorkflowListSchema=o.z.object({}),exports.MetaWorkflowGetSchema=o.z.object({workflowId:o.z.string().describe("Workflow ID to retrieve")}),exports.MetaWorkflowCreateSchema=o.z.object({name:o.z.string().min(1).describe("Unique name for the workflow"),shortName:o.z.string().min(1).max(10).describe("Short display name (required, max 10 chars)"),description:o.z.string().optional().describe("Description of what the workflow does"),testGate:o.z.enum(["off","auto","ask"]).optional().describe("Test gate: off (no test gate), auto (checks run automatically; a blocking command must pass, an advisory one may be skipped with a reason), ask (the user picks auto/interactive/skip at each completion)"),reviewGate:o.z.enum(["off","on"]).optional().describe("Review gate: off, or on (one reviewer checks each acceptance criterion, with the reviewers the kind assigns: guidance, model on engineering, any the workflow added)"),signoffGate:o.z.enum(["off","agent","you"]).optional().describe('Sign-off gate, as the workflow page names it: off; agent ("Delivery review": an agent asks whether the delivery is what was asked for, then merges or brings it to the user); you ("You sign off": the user approves before merge)'),approvalMode:o.z.enum(["none","require-approval","agent-check"]).optional().describe("Pre-work approval: none (default), require-approval (the user approves each request), or agent-check (an independent intake reviewer rules on agent-created requests before work starts)"),interactionPosture:o.z.enum(["autonomous","balanced","collaborative"]).optional().describe("Interaction posture (question-gate dial): autonomous (defaulted questions are self-answered -- proceed + FYI report), balanced (default; questions post normally, non-blocking when defaulted), collaborative (always ask the human)")}),exports.MetaWorkflowUpdateSchema=o.z.object({workflowId:o.z.string().describe("Workflow ID to update"),name:o.z.string().min(1).optional().describe("New name"),shortName:o.z.string().max(10).optional().describe("New short name (max 10 chars)"),description:o.z.string().optional().describe("New description"),testGate:o.z.enum(["off","auto","ask"]).optional().describe("Test gate: off (no test gate), auto (checks run automatically; a blocking command must pass, an advisory one may be skipped with a reason), ask (the user picks auto/interactive/skip at each completion)"),reviewGate:o.z.enum(["off","on"]).optional().describe("Review gate: off, or on (one reviewer checks each acceptance criterion, with the reviewers the kind assigns: guidance, model on engineering, any the workflow added)"),signoffGate:o.z.enum(["off","agent","you"]).optional().describe('Sign-off gate, as the workflow page names it: off; agent ("Delivery review": an agent asks whether the delivery is what was asked for, then merges or brings it to the user); you ("You sign off": the user approves before merge)'),approvalMode:o.z.enum(["none","require-approval","agent-check"]).optional().describe("Pre-work approval: none (default), require-approval (the user approves each request), or agent-check (an independent intake reviewer rules on agent-created requests before work starts)"),interactionPosture:o.z.enum(["autonomous","balanced","collaborative"]).optional().describe("Interaction posture (question-gate dial): autonomous (defaulted questions are self-answered -- proceed + FYI report), balanced (default; questions post normally, non-blocking when defaulted), collaborative (always ask the human)")}),exports.MetaRecipeListSchema=o.z.object({}),exports.MetaRecipeGetSchema=o.z.object({recipeId:o.z.string().describe("Recipe ID to retrieve")}),exports.MetaRecipeCreateSchema=o.z.object({name:o.z.string().min(1).describe("Unique name for the recipe"),description:o.z.string().optional().describe("Description of what the recipe does"),documentation:o.z.string().optional().describe("Detailed documentation")}),exports.MetaRecipeAddHookSchema=o.z.object({recipeId:o.z.string().describe("Recipe ID to add the hook to"),hookId:o.z.string().describe("Hook template ID to add"),position:o.z.number().int().min(0).optional().describe("Position in the recipe (0-based, appended if omitted)")}),exports.MetaRecipeRemoveHookSchema=o.z.object({recipeId:o.z.string().describe("Recipe ID to remove the hook from"),hookId:o.z.string().describe("Hook template ID to remove")}),exports.MetaHookListSchema=o.z.object({}),exports.MetaHookCreateSchema=o.z.object({name:o.z.string().min(1).describe("Unique name for the hook"),description:o.z.string().optional().describe("Description of what the hook does"),eventType:o.z.string().describe("Event type that triggers this hook (e.g., session_idle, request_completed, custom:plan_ready)"),category:o.z.enum(["alchemy","session","message","editing","reading","file_management","documents","history","tool"]).default("session").describe("Hook category"),agent:o.z.string().describe("Agent template to execute when hook fires"),promptTemplate:o.z.string().describe("Prompt template with {{variable}} substitution"),condition:o.z.record(o.z.any()).optional().describe("Condition object for filtering when hook fires"),timing:o.z.enum(["before","after"]).default("after").describe("When to fire relative to the event"),action:o.z.enum(["spawn_agent","inject_prompt"]).optional().describe("What the hook does: spawn_agent (default) starts a new session of `agent` with the prompt; inject_prompt sends the prompt into an existing session"),target:o.z.enum(["independent_session","child_session","same_session","parent_session","ancestor_chain"]).optional().describe("Where the prompt goes. With spawn_agent: independent_session (default, no parent) or child_session (under the session that fired the event). With inject_prompt: same_session (default, the session that fired the event), parent_session, or ancestor_chain"),maxIterations:o.z.number().int().min(1).optional().describe("Maximum times the hook fires for one session, counted from its firing record. Set it on every session_idle hook that sends into the same session. A session a hook started never triggers that hook again, whatever this says"),emitEvent:o.z.string().optional().describe("Custom event to emit on completion"),emitEventOnCondition:o.z.union([o.z.object({condition:o.z.object({field:o.z.string(),operator:o.z.enum(["contains","not_contains","equals","not_equals","matches","not_matches"]),value:o.z.string()}),event:o.z.string()}),o.z.array(o.z.object({condition:o.z.object({field:o.z.string(),operator:o.z.enum(["contains","not_contains","equals","not_equals","matches","not_matches"]),value:o.z.string()}),event:o.z.string()}))]).optional().describe("Conditional event emission based on output")}),exports.MetaWorkflowAddRecipeSchema=o.z.object({workflowId:o.z.string().describe("Workflow ID to add the recipe to"),recipeId:o.z.string().describe("Recipe ID to add"),position:o.z.number().int().min(0).optional().describe("Position in the workflow (0-based, appended if omitted)")}),exports.MetaWorkflowRemoveRecipeSchema=o.z.object({workflowId:o.z.string().describe("Workflow ID to remove the recipe from"),recipeId:o.z.string().describe("Recipe ID to remove")}),exports.MetaAgentListSchema=o.z.object({}),exports.MetaOperationsSchema=o.z.object({operation:o.z.enum(["workflow-list","workflow-get","workflow-create","workflow-update","recipe-list","recipe-get","recipe-create","recipe-add-hook","recipe-remove-hook","hook-list","hook-create","workflow-add-recipe","workflow-remove-recipe","agent-list"]).describe("Which meta operation to perform; the other params apply per operation (see tool description)"),...exports.MetaWorkflowGetSchema.partial().shape,...exports.MetaWorkflowCreateSchema.partial().shape,...exports.MetaWorkflowUpdateSchema.partial().shape,...exports.MetaRecipeGetSchema.partial().shape,...exports.MetaRecipeCreateSchema.partial().shape,...exports.MetaRecipeAddHookSchema.partial().shape,...exports.MetaRecipeRemoveHookSchema.partial().shape,...exports.MetaHookCreateSchema.partial().shape,...exports.MetaWorkflowAddRecipeSchema.partial().shape,...exports.MetaWorkflowRemoveRecipeSchema.partial().shape}),exports.TestingProcessListSchema=o.z.object({}),exports.TestingProcessGetSchema=o.z.object({processId:o.z.string().describe("Test process ID to retrieve")})
5629
+ const y=o.z.object({name:o.z.string().min(1).describe('Command name (e.g., "Build", "Unit Tests")'),command:o.z.string().min(1).describe('Shell command to run (e.g., "npm test")'),required:o.z.boolean().default(!0).describe("If true, failure blocks the request (default: true)"),timeout:o.z.number().int().min(10).max(3600).default(300).describe("Max execution time in seconds (default: 300)")})
5630
+ exports.TestingProcessCreateSchema=o.z.object({name:o.z.string().min(1).describe("Name for the test process"),environmentId:o.z.string().optional().describe("ID of the environment (confined runtime) this process runs in. Get it from environment_list or environment_setup."),description:o.z.string().optional().describe("Description of what this process verifies"),scope:o.z.string().optional().describe('LABEL ONLY -- a monorepo path prefix recorded for display (e.g. "packages/api/"). It does NOT affect when the process runs; use pathGlobs for that.'),pathGlobs:o.z.array(o.z.string()).optional().describe('Which changes this process runs on: glob patterns matched against the changed files (e.g. ["sites/**"], ["src/**", "*.md"]). THIS is what limits when the process runs. Omit it and the process runs on EVERY change, which is the right choice only for a check that is cheap and universal.'),areas:o.z.array(o.z.string()).optional().describe('Work-area labels this process covers (e.g. ["graphics/opengl"]). An alternative to pathGlobs for work that is not file-shaped; a process applies if EITHER dimension matches.'),setup:o.z.array(o.z.string()).optional().describe("Commands that prepare the tree for the tests (install the package itself, generate files the tests import), e.g. [\"python -m pip install --no-deps -e .\"]. They run in its box before its commands on every run, and also before a request's criteria checks, which run in a clean checkout of the commit where `commands` do not run: a preparation step put in `commands` is missing there and those checks fail. If one fails, the run fails as the environment's fault and the commands do not run."),commands:o.z.array(y).min(1).describe("Test commands to execute in order"),verifyAcceptanceCriteria:o.z.boolean().optional().describe("When true, auto-tester verifies request acceptance criteria after running commands"),fingerprint:o.z.array(o.z.string()).optional().describe('Files whose content invalidates setup. Setup commands re-run only when these files change between runs (e.g. ["package-lock.json"], ["Cargo.lock"], ["uv.lock", "poetry.lock"]). Polyglot repos list multiple. Omit / empty list = always re-run setup (existing behavior).'),poolSize:o.z.number().int().min(1).max(8).optional().describe("Number of warm test worktrees in the pool. Default 2. Set to 1 for languages with very large build artifacts (Rust target/, C++ build/). Higher values allow more parallel test runs at the cost of disk."),runtimeKept:o.z.string().optional().describe('Only when the user chose to run the check on a runtime other than the lowest one the project declares: that runtime and version, e.g. "python 3.12". Without it, a check whose environment runs another version than the declared minimum is not registered.'),leavesOut:o.z.array(o.z.object({what:o.z.string().describe('The left-out part in plain words, e.g. "the Valkey backend tests"'),paths:o.z.array(o.z.string()).min(1).describe('Globs for the code that part checks, so a change there goes unchecked by this check: for a backend\'s tests, that backend (e.g. ["aiocache/backends/valkey.py"]); for browser or end-to-end tests, the app source they drive (e.g. ["src/**"]). Not only the left-out test files.'),command:o.z.string().min(1).max(300).optional().describe('The command that runs that part, e.g. "pnpm test:e2e": a request whose criterion runs it is not told this part was left out.')})).optional().describe('What this check deliberately does not run and no other check runs (the suites the card lists as "not run on every change"), each with the code it checks. A change to that code is reported to the user as not checked by this check, unless the request ran that part itself.')}),exports.TestingProcessDeleteSchema=o.z.object({processId:o.z.string().describe("Test process ID to delete")}),exports.EnvironmentListSchema=o.z.object({}),exports.ResultsSchema=o.z.object({operation:o.z.enum(["record","fetch","pin","list","read"]),path:o.z.string().optional().describe("record: the file, inside the project (not /tmp); your worktree first, then the main project. Bulk that must not reach a commit can be written by a command under `.alchemy_lab/scratch/` (gitignored)."),name:o.z.string().optional().describe("record: the name a person uses for it (defaults to the filename). list: show every version recorded under this name, newest first."),summary:o.z.record(o.z.any()).optional().describe('record (required): the small facts a reader wants instead of the bytes, e.g. {maxStress: 412, unit: "MPa", converged: true}.'),box:o.z.string().optional().describe("An experiment handle (exp_...). fetch: put the bytes inside that sealed box under its /scratch (a box cannot see the host scratch; omit for host work, which is faster). record: the result lives inside that box and is streamed out and stored in one step (a box cannot write your worktree)."),mediaType:o.z.string().optional().describe("record: MIME type, when you know it."),inputs:o.z.array(o.z.string()).optional().describe("record: addresses of the results this one was made from (provenance)."),note:o.z.string().optional().describe("record: one line on how it was produced."),address:o.z.string().optional().describe("pin / read / fetch: the full 64-character address the record returned (a unique prefix works too)."),at:o.z.string().optional().describe("pin: the pointer path in your worktree (.result.json is added). fetch: where the bytes land, under AlchemyLab's scratch folder for the project on the host (the answer gives the full path) or the box's `/scratch`. Defaults to results/<name>."),comment:o.z.string().optional().describe("pin: the commit comment for the pointer file."),offset:o.z.number().optional().describe("read: line to start at (default 0)."),limit:o.z.number().optional().describe("read: how many lines (default 200). list: how many results (default 25)."),find:o.z.string().optional().describe("read: return only lines containing this text, instead of a range.")}),exports.ResultInspectSchema=o.z.object({operation:o.z.enum(["list","read"]),name:o.z.string().optional().describe("list: show every version recorded under this name, newest first."),address:o.z.string().optional().describe("read: the full 64-character address of the result, a check run's id (tr_...) or a command run's record id (trec...), to read what its commands printed."),offset:o.z.number().optional().describe("read: line to start at (default 0)."),limit:o.z.number().optional().describe("read: how many lines (default 200). list: how many results (default 25)."),find:o.z.string().optional().describe("read: return only lines containing this text, instead of a range.")}),exports.ExperimentStartSchema=o.z.object({env:o.z.string().optional().describe("Environment by name (from environment_list), one whose image has the toolchain you need."),environmentId:o.z.string().optional().describe("Environment by id (alternative to `env`). The primary env is used if neither is given."),size:o.z.enum(["light","standard","heavy"]).optional().describe("light: 2 cores (lint, a typecheck, one test file). standard (default): a share of the free cores (a suite, a build). heavy: every free core but 2 and 6 GB of memory (2 GB otherwise, unless the environment sets its own), for work that uses them (a CFD solve, meshing, a large parallel build, a model that runs out of memory). A size you do not hold opens another box."),confirmWorkspace:o.z.boolean().optional().describe('Required for env "workspace" (the live host): the task genuinely needs the real machine. Building or trying out the app does not.')}),exports.ExperimentStopSchema=o.z.object({handle:o.z.string().describe("The experiment handle to tear down.")}),exports.ExperimentListSchema=o.z.object({}),exports.ReadSiteSchema=o.z.object({url:o.z.string()}),exports.DriveSiteSchema=o.z.object({url:o.z.string().describe("The running product, e.g. the environment's published URL or http://localhost:5173."),steps:o.z.array(o.z.object({action:o.z.enum(["click","clickat","type","press","move","scroll","wait","media"]).describe('click (selector) \xb7 clickat (x,y) \xb7 type (selector + text) \xb7 press (key) \xb7 move (x,y) \xb7 scroll (dy) \xb7 wait (ms, max 5000) \xb7 media ("print" shows the printout, "screen" switches back)'),selector:o.z.string().optional().describe('Playwright selector, e.g. "text=Build" or "#start".'),text:o.z.string().optional(),key:o.z.string().optional().describe('e.g. "Enter"'),x:o.z.number().optional(),y:o.z.number().optional(),dy:o.z.number().optional(),ms:o.z.number().optional(),media:o.z.enum(["print","screen"]).optional()})).min(1).max(20),shots:o.z.enum(["each","final"]).optional().describe('"each" screenshots every step; default the final state only.'),session:o.z.string().optional().describe("Keeps the page open: the next call with this name continues where this one stopped. Idle sessions close after 10 minutes."),close:o.z.boolean().optional().describe("Close the named session after this call."),width:o.z.number().optional().describe("Viewport width for a new session (default 1280; 390 is a phone).")}),exports.CaptureSiteSchema=o.z.object({url:o.z.string(),fullPage:o.z.boolean().optional().describe("The whole scrollable page instead of the viewport."),width:o.z.number().optional().describe("Viewport width (default 1280; 390 is a phone).")}),exports.PreviewSiteSchema=o.z.object({dir:o.z.string().optional().describe('Repo-relative, e.g. "dist" or "." for the top of the repository. Not needed with stop.'),requestId:o.z.string().regex(/^req\d{6}$/).optional().describe("Serve from this unmerged request's working copy instead of main."),name:o.z.string().optional().describe("Preview handle (default: a slug of dir); reusing one replaces that preview. With stop: the preview to stop."),stop:o.z.boolean().optional().describe("Stop a running preview instead of serving one: the one named, or the only one running."),label:o.z.string().optional()}),exports.FetchAssetSchema=o.z.object({url:o.z.string().describe("The http(s) URL of the image or font to download."),destPath:o.z.string().describe('Where to write it, repo-relative (e.g. "sites/acme/assets/hero.jpg"). Must stay inside the working tree; parent directories are created.')}),exports.RequestVisualFeedbackSchema=o.z.object({box:o.z.string().optional().describe("The experiment handle (from experiment_start, on a screenshot-capable env) to render in / read from. The box must stay held until this returns."),route:o.z.string().optional().describe('With `box`: the route I render + screenshot FOR YOU (e.g. "/" or "/settings"). I serve `serveDir` and screenshot it -- you do NOT hand-roll serve/screenshot. This is the easiest path.'),script:o.z.string().optional().describe('With `box`, for FULL control: a Playwright snippet (the body of `async (page, baseUrl) => { ... }`). I serve the app, launch headless Chromium, and run your script -- navigate (page.goto(baseUrl + "/x")), click, fill, scroll, waitForSelector, etc. -- then screenshot the final page state. Reliable: you write only the interaction, no serve/launch/flags. Use this to reach a state that needs interaction (open a menu, log in, submit a form).'),fullPage:o.z.boolean().optional().describe("Capture the entire scrollable page instead of just the viewport."),serveDir:o.z.string().optional().describe("With `box`+`route`: the static dir to serve (default /work). For a built app, build first via run(), then point this at the build output (e.g. /work/dist)."),path:o.z.string().optional().describe("Alternative to route: a screenshot you ALREADY wrote inside the box (e.g. /tmp/shot.png); I read it out."),assetFilename:o.z.string().optional().describe("Alternative to box: the filename of an already-uploaded screenshot asset to annotate."),prompt:o.z.string().optional().describe("What you want the human to look at or mark up (shown with the request)."),timeoutMs:o.z.number().optional().describe("How long to wait for the human, in ms (default ~10 min).")}),exports.AskUserVisualSchema=o.z.object({question:o.z.string().describe('The question for the USER about the marked region (e.g. "Should this button use the primary color?").'),imagePath:o.z.string().optional().describe("Repo-relative path to an image you already produced (png/jpg/gif/webp), e.g. a screenshot you wrote. Provide this OR previewName."),previewName:o.z.string().optional().describe("Name of a registered live preview (a `live:` ref); I freeze it into a snapshot image for you. Provide this OR imagePath."),box:o.z.string().optional().describe('The region the question is about: "x,y,w,h" in normalized 0..1 image coordinates, origin top-left (e.g. "0.62,0.08,0.3,0.12"). Omit to ask about the whole image.'),options:o.z.array(o.z.string()).optional().describe("Optional answer choices (labels). Omit for a free-text answer."),context:o.z.string().optional().describe("Extra context shown with the question in the inbox (why you are asking, what you will do with the answer)."),priority:o.z.enum(["low","normal","high"]).optional().describe('Question priority; "high" always reaches the user regardless of autonomy dial.')}),exports.EnvironmentGetSchema=o.z.object({environmentId:o.z.string().describe("Environment ID to retrieve")}),exports.EnvironmentProvisionSchema=o.z.object({environmentId:o.z.string(),why:o.z.string().optional().describe("Why provision now (shown on the approval).")}),exports.EnvironmentTeardownSchema=o.z.object({environmentId:o.z.string()}),exports.EnvironmentStatusSchema=o.z.object({environmentId:o.z.string()}),exports.EnvironmentVerifyStackSchema=o.z.object({environmentId:o.z.string()})
5631
+ const w=o.z.object({image:o.z.string().optional().describe("Container image carrying the project toolchain/deps, e.g. node:20-alpine, python:3.12-slim, golang:1.22, ruby:3.3"),install:o.z.string().optional().describe("Deps install command -- Node-only sugar that populates a /work/node_modules cache volume, run with registry egress before the confined gate, e.g. npm ci. Non-Node runtimes use `artifacts` instead (a cache volume + prepare command: .venv/uv sync, cargo, go, vendor/bundle). Omit if the project has no deps."),composeFile:o.z.string().optional().describe("Path to the project docker-compose file for its services. Omit if no services."),shellInit:o.z.string().optional().describe("Shell preamble run before EVERY command in the box, e.g. '. /usr/lib/openfoam/openfoam2312/etc/bashrc'. REQUIRED for a toolchain that publishes itself through a script rather than the image PATH (OpenFOAM etc/bashrc, oneAPI setvars.sh, conda activate, ROS setup.bash): `docker exec` runs no ENTRYPOINT and reads no login profile, so without this every command gets a bare PATH. Put the preamble HERE, never inside the smoke command -- a smoke command carrying its own preamble proves the preamble and not the environment, and the next agent gets nothing."),connEnv:o.z.record(o.z.string()).optional().describe("Connection env injected into the gate (e.g. DATABASE_URL) using SERVICE NAMES + internal ports, never localhost/host ports."),seed:o.z.array(o.z.string()).optional().describe("Optional commands run after services are up (e.g. migrations)."),artifacts:o.z.array(o.z.object({path:o.z.string().describe("Mount target for the writable, populated volume: relative to /work for a dependency folder the project's toolchain looks for there (node_modules, .venv, vendor/bundle), or absolute (e.g. /cache/cargo). Tools you install (apt/apk packages, binaries) go at an absolute path outside /work, such as /tools: /work is the project's folder, and its test runners see anything in it."),prepare:o.z.string().optional().describe("Command that populates it -- the one phase with registry egress (e.g. npm ci, uv sync, cargo fetch). Omit for a writable empty volume."),manifests:o.z.array(o.z.string()).optional().describe("Lockfiles (relative to /work) whose content hash keys the cache; list them so the volume is reused across runs and only rebuilt when deps change (e.g. uv.lock, Cargo.lock). Omit => rebuilt every run."),env:o.z.record(o.z.string()).optional().describe('Env applied during prepare AND every run, e.g. { CARGO_HOME: "/cache/cargo" } for caches outside /work.')})).optional().describe("Per-runtime build/dependency artifacts: writable volumes populated by a prepare command, generalizing `install` beyond node_modules. Use for Python (.venv), Rust (target + $CARGO_HOME), Go, Ruby (vendor/bundle), etc. `install` is sugar for a single node_modules artifact; for any non-Node runtime use artifacts (install would write to node_modules, the wrong place)."),confinement:o.z.enum(["confined","egress-allowlist","privileged","unsafe","host","pure-host"]).optional().describe("Confinement level. Default 'confined' (fully sealed Docker; add egressAllowlist hosts to open exactly those -- stored as 'egress-allowlist'). privileged/unsafe relax the container. 'host' runs on the host machine (no Docker) inside an OS sandbox (Seatbelt/bubblewrap) for toolchains Docker can't run. 'pure-host' is the built-in workspace env (the live worktree) -- do not create new envs with it. Merge gating is independent (the Sign-off setting)."),commandGate:o.z.array(o.z.enum(["policy","agent","human"])).optional().describe("Gates an experiment command passes before it runs, in escalation order policy -> agent -> human. Empty = run freely; escalating past the last gate blocks (fail closed). policy = deterministic allowlist/deny-floor; agent = isolated LLM judge (allow or escalate only); human = ask. Registered commands are pre-approved. Defaults by level ([] for confined/egress-allowlist, ['human'] for privileged/unsafe)."),worktreeTarget:o.z.enum(["ephemeral","live"]).optional().describe("Worktree the env runs against: 'ephemeral' (a disposable copy at HEAD, default) or 'live' (the project's live working dir, read-write). The built-in workspace env is 'live'."),egressAllowlist:o.z.array(o.z.string()).optional().describe("Hosts the box may reach at the 'egress-allowlist' level (exact name or subdomain, e.g. registry.npmjs.org). Ignored at other levels."),addCaps:o.z.array(o.z.string()).optional().describe("Linux capabilities to add at the 'privileged' level (on top of cap-drop ALL), e.g. SYS_PTRACE for debuggers, IPC_LOCK for memlock. Ignored at other levels."),sysctls:o.z.record(o.z.string()).optional().describe("Namespaced sysctls to set at the 'privileged' level, e.g. net.ipv4.ip_local_port_range. Host-wide sysctls (vm.max_map_count) are NOT settable per-container."),runAsRoot:o.z.boolean().optional().describe("Run the box as root (privileged / unsafe levels). Needed for some caps + the docker socket."),dockerSocket:o.z.boolean().optional().describe("Mount the host docker socket for testcontainers-style tests. WARNING: full host control over the docker daemon. Only honored at the 'unsafe' level."),persistentVolumes:o.z.array(o.z.object({name:o.z.string(),target:o.z.string(),service:o.z.string().optional()})).optional().describe("Data volumes that survive between runs (keyed to this environment; off by default since experiments are ephemeral). Set service to mount into a compose service (e.g. a DB data dir), or omit it to mount into the box (e.g. a SQLite dir)."),resources:o.z.object({memory:o.z.string().optional().describe("Memory cap for this environment's boxes and its checks' boxes, e.g. '4g' (default 2g; 6g at size heavy). Set it when the test suite or build needs more."),cpus:o.z.number().optional().describe("A fixed CPU count. Usually leave it unset and set size instead."),size:o.z.enum(["light","standard","heavy"]).optional().describe("What this environment's boxes and checks are for, which sets their cores from what is free: light (2 cores: lint, small checks), standard (the default: a share of the free cores, for test suites and builds), heavy (every free core but 2: CFD or FEM solves, meshing, large parallel builds). An agent can ask for another size per box."),pidsLimit:o.z.number().optional().describe("Max processes (default 512)."),scratchMb:o.z.number().optional().describe("Size in MB of an in-memory /scratch, used only when the image cannot take the disk-backed one (default 512). /scratch is normally on disk and needs no size."),shmMb:o.z.number().optional().describe("/dev/shm size in MB -- bump for headless browsers (Chrome crashes on the 64m default).")}).optional().describe("Per-environment resource caps that override the confined defaults.")}),b=r(w),v='Start from a built-in preset; anything in config overrides it. "office": python-docx, openpyxl, python-pptx, pandoc, LibreOffice and segno/zbarimg (QR codes) in a sealed box, with `render-pdf FILE` to turn Word, Excel, PowerPoint, Markdown or HTML into PDF. Its image is built locally on first use (a few minutes). Pass the same preset (and config) to environment_verify and environment_create.',k="Save without a passing environment_verify, only for a config that cannot be verified from here (it needs credentials, external services or hardware the confined verifier lacks). Requires skipVerifyReason; the skip is logged."
5632
+ exports.EnvironmentCreateSchema=o.z.object({name:o.z.string().min(1).describe("Name for the environment, e.g. node + postgres"),description:o.z.string().optional().describe("What this environment provides"),scope:o.z.string().optional().describe("Subproject path prefix for monorepos (e.g. packages/api/). Omit for the whole repo."),preset:o.z.enum(["office"]).optional().describe(v),config:b.optional().describe("The exact config (after the preset) that passed environment_verify in this session, unless skipVerify; its fields are described on environment_verify. Optional with a preset."),isPrimary:o.z.boolean().optional().describe("Make this the project primary environment (default for new test processes). The first environment is primary automatically."),skipVerify:o.z.boolean().optional().describe(k),skipVerifyReason:o.z.string().optional().describe("Why this config cannot be verified (required with skipVerify: true; recorded in the log).")}),exports.EnvironmentUpdateSchema=o.z.object({environmentId:o.z.string(),name:o.z.string().min(1).optional(),description:o.z.string().optional(),scope:o.z.string().optional(),config:b.optional().describe("Replaces the config wholesale: the exact config that passed environment_verify in this session, unless skipVerify (fields described on environment_verify). Metadata-only updates need no verify."),isPrimary:o.z.boolean().optional().describe("Make this the project primary environment"),skipVerify:o.z.boolean().optional().describe(k),skipVerifyReason:o.z.string().optional().describe("Why this config cannot be verified (required with skipVerify: true; recorded in the log).")}),exports.EnvironmentDeleteSchema=o.z.object({environmentId:o.z.string().describe("Environment ID to delete")}),exports.EnvironmentVerifySchema=o.z.object({preset:o.z.enum(["office"]).optional().describe(v),config:w.optional().describe("The proposed environment config to verify (image, install, services, connection). Optional with a preset."),smoke:o.z.string().optional().describe("Optional smoke command run confined after the environment is up (default: true). Use a connection probe to confirm services are reachable.")}),exports.EnvironmentSetupSchema=o.z.object({name:o.z.string().max(60).optional().describe("A few words naming what you need (e.g. 'Node 20 for syntax checks')."),context:o.z.string().optional().describe("What you need and why, for the setup architect (e.g. 'Node 20 to run node --check on standalone .js files; no deps').")}),exports.SetupFinishSchema=o.z.object({outcome:o.z.enum(["ready","declined","could_not_finish","no_code","not_yet"]).describe("How the run ended. 'ready' needs something saved in this run."),summary:o.z.string().min(1).describe("What was set up (names and ids), and an answer to every ask the run carries: done, or not done and why. Plain words; it reaches the waiting workers and the user."),startsAfter:o.z.string().regex(/^req\d{6}$/).optional().describe("With 'not_yet': the request still writing what this setup registers.")}),exports.TestingProcessUpdateSchema=o.z.object({processId:o.z.string(),environmentId:o.z.string().optional(),name:o.z.string().min(1).optional(),description:o.z.string().optional(),scope:o.z.string().optional().describe("A display label only; pathGlobs decides when the process runs."),pathGlobs:o.z.array(o.z.string()).optional().describe('Globs matched against changed files (e.g. ["src/**", "*.md"]): the changes this process runs on. Replaces the list; [] means every change.'),areas:o.z.array(o.z.string()).optional().describe("Work-area labels this process covers; it applies when pathGlobs or areas match."),isActive:o.z.boolean().optional(),setup:o.z.array(o.z.string()).optional().describe("Replaces the setup commands (run in the check's box before its commands, and before the criteria checks in their clean checkout)."),commands:o.z.array(y).optional().describe("Replaces the test commands."),verifyAcceptanceCriteria:o.z.boolean().optional().describe("The auto-tester also verifies the request's acceptance criteria."),fingerprint:o.z.array(o.z.string()).optional().describe("Files whose content invalidates setup."),leavesOut:o.z.array(o.z.object({what:o.z.string().describe('The left-out part in plain words, e.g. "the Valkey backend tests"'),paths:o.z.array(o.z.string()).min(1).describe("Globs for the code that part checks (for end-to-end tests, the app source they drive), not only its test files."),command:o.z.string().min(1).max(300).optional().describe('The command that runs that part, e.g. "pnpm test:e2e".')})).optional().describe("Replaces what this check deliberately does not run, with the code each part checks; [] clears it."),poolSize:o.z.number().int().min(1).max(8).optional().describe("Warm test worktrees in the pool."),runtimeKept:o.z.string().optional().describe('With environmentId: only when the user chose a runtime other than the lowest one the project declares, e.g. "python 3.12".')}),exports.TestsSchema=o.z.object({operation:o.z.enum(["list","setup","run","switch-off","switch-on"]),process:o.z.string().optional().describe("run, switch-off, switch-on: one test process by name or id (run: omit for all active ones)."),userSaid:o.z.string().max(600).optional().describe("switch-off / switch-on: the user's words asking for it, copied exactly."),name:o.z.string().optional().describe("run: one test command by name; omit for all required commands."),ask:o.z.string().max(1500).optional().describe("setup, required outside a request: what the user asked the check to run, in their words; the setup architect registers exactly that.")}),exports.ExecuteTestCommandSchema=o.z.object({processId:o.z.string().describe("Test process ID containing the command"),commandName:o.z.string().describe('Name of the test command to run, or "setup" to run all setup commands in sequence')}),exports.RunSchema=o.z.object({command:o.z.string().optional().describe("A shell command, run in the box (pass box or env)."),name:o.z.string().optional().describe("A saved command by name, instead of command."),box:o.z.string().optional().describe("An experiment handle from experiment_start."),env:o.z.string().optional().describe("Instead of box: an environment by name; its box is started (or your open one reused) and the result gives the handle."),size:o.z.enum(["light","standard","heavy"]).optional().describe("With env: the box size (see experiment_start)."),args:o.z.string().optional(),grep:o.z.string().optional().describe("Filter output through grep -i with this pattern."),timeout:o.z.number().optional().describe("Seconds."),why:o.z.string().optional().describe("One short sentence, shown on the approval card when the command needs the user's approval."),cwd:o.z.string().optional().describe('A subdirectory for an ad-hoc command (e.g. "apps/web"); a command starting with `cd` is refused in favour of this.')}),exports.CommandsSchema=o.z.object({operation:o.z.enum(["run","list","remove","register","setup"]).default("run").describe('list, setup, register or remove ("run" is the run tool\'s job).'),name:o.z.string().optional().describe("remove: the command name."),args:o.z.string().optional(),grep:o.z.string().optional(),command:o.z.string().optional(),timeout:o.z.number().optional(),cwd:o.z.string().optional(),context:o.z.string().optional().describe("setup: the command wanted, where it runs and what it is for."),commands:o.z.array(o.z.object({name:o.z.string().min(1).describe('e.g. "test:web"'),command:o.z.string().min(1),description:o.z.string().min(1).describe("What this command verifies."),cwd:o.z.string().optional().describe("Relative to the project root (monorepo subdirs); omit for the root."),timeout:o.z.number().optional().describe("Seconds (default 60)."),environment:o.z.string().optional().describe('The environment it runs in, by name (environment_list). Omitted, it goes where you ran it (a bare box with no saved environment is refused, so name one). Name "Workspace" only when it truly needs the host.'),target:o.z.string().optional().describe("The id your setup instructions give for a target this command prints the number for.")})).optional().describe("register: the commands to register.")}),exports.ReportTestResultsSchema=o.z.object({status:o.z.enum(["passed","failed","error"]).describe("Overall result"),testRunId:o.z.string().optional().describe("The test run this verdict belongs to (given in your instructions). Strongly preferred: without it the latest run is guessed, which misattributes results when several testers run concurrently."),results:o.z.object({commands:o.z.array(o.z.object({name:o.z.string().describe("Command name"),status:o.z.enum(["passed","failed","skipped","error"]).describe("Command result"),output:o.z.string().optional().describe("Relevant output snippet"),diagnosis:o.z.string().optional().describe("Why it failed, if applicable")})).describe("Per-command results"),summary:o.z.string().describe("Brief overall summary"),acceptanceCriteria:o.z.array(o.z.object({criterion:o.z.string().describe("The acceptance criterion text"),status:o.z.enum(["verified","unverified","unclear"]),evidence:o.z.string().describe("How verified, or why not")})).optional().describe("AC verification results, if applicable"),faultClass:o.z.enum(["fail_code","fail_evidence","fail_environment","fail_process"]).optional().describe("On a FAILED verdict, WHY it failed so the gate routes to the right actor: 'fail_code' (the change is wrong), 'fail_evidence' (the run did not prove a criterion the coder could have proven: attach/adjust verify commands), or 'fail_environment' (a required tool/runtime is MISSING from the confined box, e.g. 'node: not found': the coder cannot fix this; the environment must be extended). Use 'fail_environment' ONLY when the evidence shows a command/runtime absent from the box, never for a genuine defect or a fixable evidence gap. 'fail_process' is for a test process whose OWN command names a file the repository does not have (a deleted script): nobody's code is wrong and extending the box cannot help; the process itself must be fixed or turned off."),missingCapabilities:o.z.array(o.z.string()).optional().describe("With faultClass 'fail_environment', the binaries/runtimes the box lacks (e.g. ['node']) so the environment can be extended to provide them.")}).describe("Structured test results")}).superRefine((e,t)=>{"fail_environment"!==e.results?.faultClass||e.results.missingCapabilities&&e.results.missingCapabilities.length>0||t.addIssue({code:o.z.ZodIssueCode.custom,path:["results","missingCapabilities"],message:"faultClass 'fail_environment' requires results.missingCapabilities: name the absent binaries/runtimes (the deterministic capability probe in your evidence lists them, e.g. ABSENT from the box: node). Without the names, the environment cannot be extended and the request strands."})})
5633
+ const I=o.z.string().min(1,"every option needs its consequence (description)").max(200,"an option's description is its consequence in one line: 200 characters at most").describe("Its consequence in one line: what it gets and costs."),$=o.z.string().min(1).max(120,"because is one clause: 120 characters at most")
5634
+ exports.OpeningBriefSectionSchema=o.z.object({id:o.z.string().min(1).describe('Unique within the brief ("date-format").'),question:o.z.string().min(1).describe("The choice, one plain question answerable without your session."),context:o.z.string().min(1).describe("What it shapes, citing the request and its sources as stated; where they answer it, recommend their answer."),options:o.z.array(o.z.object({id:o.z.string().min(1),label:o.z.string().min(1),description:I})).min(2).describe("At least two genuine alternatives."),default:o.z.string().min(1).describe("The option you proceed on now (shown recommended)."),because:$.describe("Why, in one clause."),criteria:o.z.array(o.z.string().min(1)).optional().describe("Keys of criteria whose wording this choice decides (worded for your default); another pick marks them for rewording.")}).superRefine((e,t)=>{e.options.some(t=>t.id===e.default)||t.addIssue({code:o.z.ZodIssueCode.custom,path:["default"],message:`default '${e.default}' names no option in this section (option ids: ${e.options.map(e=>e.id).join(", ")})`}),"testing-mode"===e.id&&t.addIssue({code:o.z.ZodIssueCode.custom,path:["id"],message:"section id 'testing-mode' is reserved: the server composes the testing section when the project's gate needs it -- remove it from your sections"})}),exports.SessionMessageOperationsSchema=o.z.object({operation:o.z.enum(["send","note","reply","list","get","offer-handoff","record-decision","brief","withdraw"]),milestone:o.z.boolean().optional().describe("note: a real boundary (it works, the approach changed, the goal is met); one quiet line in the user's stream, a few per request at most."),percent:o.z.number().min(0).max(100).optional().describe("note: how far along your work on this request is; it may go down."),withdrawReason:o.z.string().optional().describe("withdraw: why the answer is no longer needed."),type:o.z.enum(["question","report"]).optional().describe("Required for send."),toSessionId:o.z.string().optional().describe('A session id, or "parent". Omit for the user (a broadcast).'),questionType:o.z.enum(["free-form","alternatives"]).optional().describe("Required for a question."),questionContent:o.z.object({question:o.z.string().min(1).describe("As the user reads it; a criterion by its words, never its key."),context:o.z.preprocess(e=>null!==e&&"object"==typeof e?JSON.stringify(e):e,o.z.string().optional()).optional().describe("What the user needs to answer without your session: what you found and why it matters. No paths or identifiers; output they should judge goes in a fenced block, as printed."),options:o.z.array(o.z.object({id:o.z.string(),label:o.z.string(),description:I,recommended:o.z.boolean().optional().describe("Your advice, highlighted (what happens unanswered is defaultOption). Not with criteria. Never on an option that makes up what the user has not given (estimates, sample values, invented names): leave it visibly empty or marked unknown."),because:o.z.preprocess(a,$.optional()).describe("With recommended (required there): why, in one clause."),notePrompt:o.z.string().min(3).max(120).optional().describe('For an option only useful with the user\'s words ("I want changes"): the question its text field asks ("What should change?"); the pick arrives with what they typed.'),effect:o.z.enum(["choose","send-back","not-yet"]).optional().describe('"choose" (default): records the pick. "send-back": asks for a change; on a request awaiting sign-off the pick itself sends it back (no reopen). "not-yet": [user-input] criteria only; they stay owed.')})).optional().describe("Genuine alternatives, each complete in one tap; recommended first. When the user's way cannot work, include one reaching their goal another way."),allowMultiple:o.z.boolean().optional(),fields:o.z.array(o.z.object({id:o.z.string().min(1),label:o.z.string().min(1),placeholder:o.z.string().optional()})).min(1).optional().describe('free-form: one labelled input per value; answers arrive as "Label: value" lines. Never ask for passwords or keys: answers are on the record.'),defaultOption:o.z.string().optional().describe("What happens if nobody answers before expiry (option id, or text for free-form); the asker resumes. It happens without the user, so it is the SAFE option when options differ in risk (silent value changes, data loss, made-up data, anything hard to undo), even if you recommend another; the context says so."),onExpiry:o.z.enum(["assume-default","escalate"]).optional().describe('"assume-default" (default with a defaultOption) or "escalate": stays pending for the user (on Self-driving only priority "high" reaches them).'),steer:o.z.enum(["what","how"]).optional().describe('"what" shapes the product (spec, wording, UX, scope); "how" the process (testing, sequencing), mostly yours to decide, not ask.'),changeableLater:o.z.boolean().optional().describe("true when the answer can change later without loss (nothing sent, deleted or published on it).")}).superRefine((e,t)=>{(e.options??[]).forEach((e,r)=>{!0!==e.recommended||e.because||t.addIssue({code:o.z.ZodIssueCode.custom,path:["options",r,"because"],message:`option '${e.id}' is recommended: say why in one clause (because)`})})}).optional().describe("Required for a question. Before asking the user: when context answers it and a wrong guess is cheap to fix, proceed. Otherwise ask with a defaultOption unless only the user can answer. Under 'autonomous' the default returns at once; 'balanced' holds up to ten minutes, then continues; 'collaborative' holds briefly, then ends your turn to wait. One decision per question, related uncertainties bundled; several candidate next steps are one alternatives question. A question the user already decided returns their decision: proceed on it."),priority:o.z.enum(["low","normal","high"]).optional().describe('"high": blocked with real stakes; reaches the user at once. "low" with a defaultOption: under \'balanced\', batched to the next checkpoint without holding.'),expiresInHours:o.z.number().optional(),userSaid:o.z.string().min(8).max(600).optional().describe('question: when the user asked to be asked ("ask me first"), their words exactly (checked); it then reaches them at any Autonomy.'),replaces:o.z.array(o.z.string().regex(/^Q-[A-Za-z0-9]+-\d+$/)).max(10).optional().describe("question: your open questions on the request this supersedes (they close). With one open, pass this or keepsOpen."),keepsOpen:o.z.boolean().optional().describe("question: it asks something else; your open ones stay open."),forceAsk:o.z.boolean().optional().describe("question: re-ask what the decision record answers, only because circumstances changed (say what in context)."),status:o.z.enum(["success","partial","failure","blocked"]).optional().describe("report: how it ended. Omitted reads success, or blocked with blockedOn."),blockedOn:o.z.string().optional().describe('Required with status "blocked" on your request: "decision" (the user\'s open card on it, else a question to your parent), a card code ("Q-AB12CD34-001"), or a request id (a wait; you are told when it settles).'),criteria:o.z.array(o.z.string().min(1)).max(10).optional().describe('question: keys of the [user-input] criteria you ask for; only this counts as asking them. No default, no recommended option; the answer is their proof unless it is "not-yet". With a "not-yet" option you build on a placeholder meanwhile (Self-driving answers it at once); without one you wait at every Autonomy. Their check of finished work is asked on the end card, not here.'),attention:o.z.enum(["fyi","glance","act"]).optional().describe("'fyi' (no badge), 'glance', 'act'. Default from status: failure/blocked act, partial glance, success fyi."),reportKind:o.z.enum(["milestone","reply"]).optional().describe("'reply': answers the user's inbox message."),summary:o.z.string().optional().describe("Required for a report: outcome first, subject named first (it shows alone, often hours later), paths in details."),details:o.z.string().optional().describe("With blockedOn \"decision\", the question's context (maybe the user's card): plain words, no tool names; explain a refusal, never paste it."),ruleVerdicts:o.z.array(o.z.object({rule:o.z.string().min(1).max(80).describe("The guidance id, no brackets."),verdict:o.z.enum(["held","broken","not_applicable"]),note:o.z.string().max(300).optional().describe("broken: what and where (file:line).")})).max(40).optional().describe("report, Guidance reviewer: a verdict on every item you were given."),silent:o.z.boolean().optional().describe("Record without waking the coordinator (fan-out research)."),relatesTo:o.z.string().regex(/^[IQ]-[A-Za-z0-9]+-\d+$/,"relatesTo must be an instruction code (I-...) or question code (Q-...)").optional().describe("An instruction code (I-...); for record-decision, the question (Q-...) it resolves."),decision:o.z.string().optional().describe("record-decision (required): the one-line call."),why:o.z.string().optional().describe("record-decision: the reasoning."),context:o.z.string().optional().describe("record-decision: what the choice was about."),requestId:o.z.string().optional().describe("The request it is about, so it shows there (note: defaults to yours; brief: required); without it a report or decision is filed at the project."),area:o.z.string().optional().describe("record-decision: a work area the call is about (without requestId)."),sections:o.z.array(exports.OpeningBriefSectionSchema).min(1).optional().describe("brief (required): your real design choices."),messageCode:o.z.string().optional().describe("Required for reply, get and withdraw."),amount:o.z.number().positive().max(1e5).optional().describe("Dollars the user named, their words in quote: 'build' on a Plan ready card sets the plan's budget; 'allow' on a budget card allows that much more."),sectionAnswers:o.z.record(o.z.string(),o.z.string().nullable()).optional().describe("reply to an opening brief: { sectionId: optionId } for sections the user answered, changed or confirmed, with quote; null when one no longer applies; 'your-words' when no option says what they asked. Unnamed sections stay open; a change sends finished work back to rework."),quote:o.z.string().optional().describe("reply: the user's words this answer records, exactly (refused if they never wrote them); omit for your own decision. Options that are the user's own statement (\"I checked, it works\") only they can pick."),text:o.z.string().optional().describe("reply: a free-form answer. note (required): the note."),selectedOptions:o.z.array(o.z.string()).optional().describe("reply: the picked option ids."),notes:o.z.string().optional(),escalate:o.z.boolean().optional().describe("reply to a question to you that needs the user: a copy reaches them with your recommendation (notes); the asker gets their answer. Not for broadcasts."),list:o.z.object({sessionId:o.z.string().optional().describe("Defaults to your session."),messageType:o.z.enum(["question","report","instruction","all"]).default("all"),direction:o.z.enum(["incoming","outgoing","all"]).default("all"),status:o.z.enum(["pending","answered","expired","success","partial","failure","blocked","all"]).default("all"),readStatus:o.z.enum(["unread","read","acknowledged","all"]).default("all"),requestId:o.z.string().optional().describe("Only messages about this request."),limit:o.z.number().min(1).max(100).default(50),offset:o.z.number().min(0).default(0)}).optional(),offerHandoff:o.z.object({summary:o.z.string().describe("One sentence: what the plan builds."),requestIds:o.z.array(o.z.string()).describe("Requests created from the plan.")}).optional()}).superRefine((e,t)=>{const r=n(e)
5635
+ r&&t.addIssue({code:o.z.ZodIssueCode.custom,message:r})}),exports.CommitToViewedSessionSchema=o.z.object({message:o.z.coerce.string().min(1).describe("The cleaned-up user message to post to the viewed session. Fix obvious dictation errors, add punctuation, but preserve the user's intent exactly.")}),exports.DirectiveOperationsSchema=o.z.object({operation:o.z.enum(["set","list","search-decisions"]).describe("search-decisions = free-text search the project's decision + annotation record"),targetType:o.z.enum(["project","area","request","you"]).optional(),targetId:o.z.string().optional(),body:o.z.string().max(2e3).optional(),note:o.z.string().optional(),userSaid:o.z.string().optional(),revises:o.z.string().max(160).optional(),status:o.z.string().optional(),query:o.z.string().max(200).optional().describe("search-decisions: the search text, matched against recorded decisions (question + answer) and annotations (comment body + quoted text). Required for search-decisions."),limit:o.z.number().int().min(1).max(50).optional().describe("search-decisions: max matches per record type (default 10).")}),exports.McpConnectionsSchema=o.z.object({operation:o.z.enum(["list","propose","update","remove"]).describe("list = the connections this project has; propose = register one, switched off, for the user to switch on; update = correct one by name (only the fields you pass change; a connection that was on goes off for the user to switch on again); remove = take back one that is switched off."),name:o.z.string().optional().describe("propose: the connection name, lower case letters, digits and dashes. It becomes the tool prefix (name_tool). update / remove: the name of the connection to change."),transport:o.z.enum(["repo","boxed","remote"]).optional().describe("propose / update: repo = a server in THIS repository, built from its Dockerfile and run in a confined box (the repository is mounted read-only at /work, /scratch is writable memory, the image ENTRYPOINT is what runs, rebuilt when its files change on main); boxed = a published npm package at an exact version, installed once and run in a box; remote = a hosted server reached by url."),dockerfile:o.z.string().optional().describe("propose / update repo: path of the Dockerfile inside the repository, e.g. mcp/server.Dockerfile."),context:o.z.string().optional().describe("propose / update repo: the docker build context directory inside the repository (default: the repository root)."),package:o.z.string().optional().describe("propose / update boxed: npm package with an exact version, e.g. @scope/server@1.2.3."),bin:o.z.string().optional().describe("propose / update boxed: the bin to run, the name under node_modules/.bin."),url:o.z.string().optional().describe("propose / update remote: the http(s) url."),environment:o.z.record(o.z.string()).optional().describe("propose / update: plain KEY=value configuration (headers for remote). Never put a secret here; name it in secretKeys instead."),secretKeys:o.z.array(o.z.string()).optional().describe("propose / update: names of environment variables (or headers) whose VALUES are secret. The user sets the values on the machine that runs the work; they never reach the database.")}),exports.AnswerQuestionSchema=o.z.object({messageCode:o.z.string().min(1).describe("The code in square brackets from <waiting_on_you>, e.g. Q-51209THD-005."),optionId:o.z.string().optional().describe("The id of the option the user picked, when the question has options."),text:o.z.string().optional().describe("The user's answer in their own words, cleaned up, when the question has no options or they said something the options do not cover.")})},19567(e,exports,t){exports.Server=exports.SSEServerTransport=exports.StdioServerTransport=void 0
5612
5636
  const r=t(66865)
5613
5637
  Object.defineProperty(exports,"Server",{enumerable:!0,get:function(){return r.Server}})
5614
5638
  const n=t(25802)
@@ -5885,8 +5909,8 @@ throw g.error(t,{error:e instanceof Error?e.stack:String(e)}),new Error(t)}const
5885
5909
  g.info("API client initialized with specialized clients"),I?(R.setAuthToken(I),g.info("Auth token set on ApiClient during creation",{hasToken:!0,tokenLength:I.length})):g.warn("No auth token available during ApiClient creation",{info:"Client will need to authenticate before making requests"})
5886
5910
  const A=v.verifyAllClients()
5887
5911
  A.success?g.info("Token consistency verified across all clients"):g.error(`Token inconsistency detected in ${A.failedClients.length} clients: ${A.failedClients.join(", ")}`)
5888
- const P=R.getAuthToken()
5889
- return I&&!P?(g.error("CRITICAL: ApiClient token was not set properly!"),R.setAuthToken(I)):P&&g.info("ApiClient token verified",{tokenLength:P.length,matches:P===I}),g.info("API client creation completed successfully"),R}}},26848(e,exports,t){exports.ClientTokenSynchronizer=void 0
5912
+ const j=R.getAuthToken()
5913
+ return I&&!j?(g.error("CRITICAL: ApiClient token was not set properly!"),R.setAuthToken(I)):j&&g.info("ApiClient token verified",{tokenLength:j.length,matches:j===I}),g.info("API client creation completed successfully"),R}}},26848(e,exports,t){exports.ClientTokenSynchronizer=void 0
5890
5914
  const r=t(58824)
5891
5915
  exports.ClientTokenSynchronizer=class{constructor(e){this.clients=new Set,this.logger=e.child({component:"client-token-synchronizer"})}registerClient(e){this.clients.add(e),this.logger.debug(`Registered client: ${e.constructor.name}, total clients: ${this.clients.size}`)
5892
5916
  const t=e.getAuthToken()
@@ -6551,15 +6575,17 @@ if(!t)return`NOT-MEASURED-YET:it is measured after the work is completed, on the
6551
6575
  const n=String(t.note??"").replace(/\s+/g," ").trim().slice(0,300)
6552
6576
  return`${"met"===t.verdict?"MEASURED-MET":"unmet"===t.verdict?"MEASURED-WORSE":"MEASURED"}:${n||"measured"}; ${r}`}const o=function(e){const t=e?.proof?.checkSetup
6553
6577
  return"string"==typeof t&&t?`its check starts when the request is completed: set up at completion (setup run ${t}). The check runs what this request adds, so it is registered once the request is completed, and its first run on main is the proof, written on the criterion then. Decided by that run only, never by a review: registering the check is not a part of this request left undone. What the check will run is in the diff and is yours to read`:null}(e)
6554
- return o?`CHECK-AT-COMPLETION:${o}`:!0===e?.proven?"reviewer"===t.by?"PROVEN:review":"you"===t.by?"PROVEN:user-hand-check":"driver"===t.by?"PROVEN:drive":"PROVEN:test":"not-checked"===n.driver?.verdict?"NOT-CHECKED:drive":"answer"===t.reword?.from?`REWORD:${String(t.reword.note??"the answer it was written for changed").slice(0,300)}; reword it with request_operations update, its key and userSaid "${t.reword.ref}"`:t.notARealTest?"NOT-A-REAL-TEST":t.checkFails?"met"===n.reviewer?.verdict?"FAILED:test (review met, check fails)":"FAILED:test":t.disputed?`DISPUTED:its check passes, but the reviewer says it does not hold${t.disputed.note?` ("${String(t.disputed.note).slice(0,200)}")`:""}; strengthen the check so it tests what the criterion says, or fix the code`:"could-not-run"===n.instrument?.verdict?"COULD-NOT-RUN:test (its check could not run here; it says nothing either way)":"unmet"===n.reviewer?.verdict?"UNMET:review":!0===n.reviewer?.reword?"REWORD:a reviewer found its words no longer fit what was asked; reword it with the user's words, or ask them":"withdrawn"===n.reviewer?.verdict?"RE-REVIEW:its review was withdrawn (the work changed after it, or a new pass is due)":e?.coder?"ATTESTED":"UNPROVEN"}function o(e){const r=new Map
6578
+ return o?`CHECK-AT-COMPLETION:${o}`:!0===e?.proven?"reviewer"===t.by?"PROVEN:review":"you"===t.by?"PROVEN:user-hand-check":"driver"===t.by?"PROVEN:drive":"PROVEN:test":"not-checked"===n.driver?.verdict?"NOT-CHECKED:drive":"answer"===t.reword?.from?`REWORD:${String(t.reword.note??"the answer it was written for changed").slice(0,300)}; reword it with request_operations update, its key and userSaid "${t.reword.ref}"`:t.notARealTest?"NOT-A-REAL-TEST":t.checkFails?"met"===n.reviewer?.verdict?"FAILED:test (review met, check fails)":"FAILED:test":t.disputed?`DISPUTED:its check passes, but the reviewer says it does not hold${t.disputed.note?` ("${String(t.disputed.note).slice(0,200)}")`:""}; strengthen the check so it tests what the criterion says, or fix the code`:"could-not-run"===n.instrument?.verdict?"COULD-NOT-RUN:test (its check could not run here; it says nothing either way)":"unmet"===n.reviewer?.verdict?"UNMET:review":!0===n.reviewer?.reword?"REWORD:a reviewer found its words no longer fit what was asked; reword it with the user's words, or ask them":"withdrawn"===n.reviewer?.verdict?"RE-REVIEW:its review was withdrawn (the work changed after it, or a new pass is due)":e?.coder?"ATTESTED":"UNPROVEN"}function o(e){const t=String(e??"").trim(),r=/^\[?(\d+[a-z])\](?:\s|$)/i.exec(t)??/^(\d+[a-z])$/i.exec(t)
6579
+ return r?r[1].toLowerCase():t}function s(e){const r=new a
6555
6580
  for(let n=0;n<e.length;n++){const o=t(e[n].id,n)
6556
- r.set(o,e[n])}return r}function s(e){if(0===e.length)return"No acceptance criteria defined."
6557
- const t=o(e),r=[]
6581
+ r.set(o,e[n])}return r}function i(e){if(0===e.length)return"No acceptance criteria defined."
6582
+ const t=s(e),r=[]
6558
6583
  for(const[e,o]of t){const t=n(o),s="objective"===o.kind||"subjective"===o.kind||"gate"===o.kind?` [${o.kind.toUpperCase()}]`:"",i=o.standing?o.waived?" [WAIVED for this request by the user; it no longer binds, do not work on or judge it]":` [FROM THE ${o.standing.processName?`PROCESS "${String(o.standing.processName).slice(0,60)}"`:"WORKFLOW"}: every request that follows it carries it; it cannot be dropped or reworded; if it does not apply, the guidance tool with guidanceId "[guidance:${o.standing.ruleKey?String(o.standing.ruleKey):String(o.standing.id??"")}]": exception when the user said so, else conflict]`:"",a="string"==typeof o.environment&&o.environment.trim()?` [its checks run in the "${o.environment.trim().slice(0,80)}" environment]`:""
6559
6584
  r.push(`[${e}] [${t}]${s}${i}${a} ${o.description}`)}return r.join("\n")}exports.formatCriteriaWithHashes=void 0,exports.criterionShortKey=t,exports.isUserOwnCheck=r,exports.latestRow=function(e,t){const r=e?.ledger
6560
- if(Array.isArray(r))for(let e=r.length-1;e>=0;e--)if(t.includes(r[e]?.source))return r[e]},exports.criterionProven=function(e){return!0===e?.proven},exports.buildCriteriaKeyMap=o,exports.formatCriteriaWithKeys=s,exports.formatVerifyInstructions=function(e){const t=o(e),r=[]
6585
+ if(Array.isArray(r))for(let e=r.length-1;e>=0;e--)if(t.includes(r[e]?.source))return r[e]},exports.criterionProven=function(e){return!0===e?.proven},exports.buildCriteriaKeyMap=s,exports.formatCriteriaWithKeys=i,exports.criteriaKeyChoices=function(e){return[...s(e)].map(([e,t])=>` "${e}": ${String(t.description??"").slice(0,120)}`).join("\n")},exports.formatVerifyInstructions=function(e){const t=s(e),r=[]
6561
6586
  for(const[e,n]of t)r.push(` {"key": "${e}", "evidence": "<your evidence for: ${n.description}>"}`)
6562
- return`Use the merge operation with evidence for each criterion:\n\n${s(e)}\n\nExample call:\n{\n "operation": "merge",\n "requestId": "<requestId>",\n "merge": {\n "verifications": [\n${r.join(",\n")}\n ]\n }\n}`},exports.formatCriteriaWithHashes=s},82960(e,exports){function t(e,t={}){const{logger:r,operationName:n="API operation",throwOnNoData:o=!1,defaultValue:s=null,includeMetadata:i=!1}=t
6587
+ return`Use the merge operation with evidence for each criterion:\n\n${i(e)}\n\nExample call:\n{\n "operation": "merge",\n "requestId": "<requestId>",\n "merge": {\n "verifications": [\n${r.join(",\n")}\n ]\n }\n}`}
6588
+ class a extends Map{get(e){return super.get(e)??super.get(o(e))}has(e){return super.has(e)||super.has(o(e))}}exports.formatCriteriaWithHashes=i},82960(e,exports){function t(e,t={}){const{logger:r,operationName:n="API operation",throwOnNoData:o=!1,defaultValue:s=null,includeMetadata:i=!1}=t
6563
6589
  if(r&&r.debug(`${n} - Response structure analysis`,{type:typeof e,isApiResponse:e&&"object"==typeof e&&"success"in e,isSuccessResponse:e&&"object"==typeof e&&!0===e.success,isErrorResponse:e&&"object"==typeof e&&!1===e.success,hasData:e&&"object"==typeof e&&"data"in e,hasMetadata:e&&"object"==typeof e&&"metadata"in e,properties:e&&"object"==typeof e?Object.keys(e):[],dataPreview:e?JSON.stringify(e).substring(0,200)+"...":"null"}),null==e){if(r&&r.warn(`${n} - Response is null or undefined`),o)throw new Error(`${n}: Response is null or undefined`)
6564
6590
  return i?{data:s,metadata:void 0}:s}if("object"!=typeof e||!("success"in e))return r&&(r.warn(`${n} - Response is not a standard API response (missing success property)`),r.debug(`${n} - Attempting to use response directly as data`)),i?{data:e,metadata:void 0}:e
6565
6591
  if(!1===e.success){const t=e,a=t.error?`${t.error.code}: ${t.error.message}`:"Unknown error"
@@ -7596,13 +7622,15 @@ const i=setInterval(()=>{s+=1
7596
7622
  const t=e.message?.()
7597
7623
  n({method:"notifications/progress",params:{progressToken:r,progress:s,...t?{message:t}:{}}}).catch(()=>{})},o)
7598
7624
  try{return await t()}finally{clearInterval(i)}}exports.withHeartbeat=r,exports.runTrackedShellWithHeartbeat=function(e,t,o,s){return r({progressToken:s?.progressToken,sendNotification:s?.sendNotification,message:()=>`running ${o.name}`},()=>(0,n.runTrackedShellCommand)(e,t,o))}
7599
- const n=t(44600)},49779(e,exports){exports.x4=exports.Tt=void 0,exports.validateServerName=function(e){return exports.x4.test(e)?exports.Tt.includes(e)?`"${e}" is reserved`:null:"Connection name must be 2-39 characters, lower-case letters, digits and dashes, starting with a letter"},exports.validateRepoConfig=function(e){if(void 0!==e.command)return"A repository connection derives its own command from the image; give it a dockerfile instead"
7600
- const t=e=>{const t=e.replace(/\\/g,"/")
7601
- return!t.startsWith("/")&&!/^[a-zA-Z]:/.test(t)&&!t.split("/").includes("..")},r=e.dockerfile
7602
- if("string"!=typeof r||!r.trim())return"A repository connection needs the dockerfile to build, as a path inside the repository, for example mcp/server.Dockerfile"
7603
- if(!t(r.trim()))return`dockerfile must be a path inside the repository, not "${r}"`
7625
+ const n=t(44600)},49779(e,exports){function t(e){return/[\r\n]/.test(e)||e.trim().length>240}exports.x4=exports.Tt=void 0,exports.validateServerName=function(e){return exports.x4.test(e)?exports.Tt.includes(e)?`"${e}" is reserved`:null:"Connection name must be 2-39 characters, lower-case letters, digits and dashes, starting with a letter"},exports.validateRepoConfig=function(e){if(void 0!==e.command)return"A repository connection derives its own command from the image; give it a dockerfile instead"
7626
+ const r=e=>{const t=e.replace(/\\/g,"/")
7627
+ return!t.startsWith("/")&&!/^[a-zA-Z]:/.test(t)&&!t.split("/").includes("..")},n=e.dockerfile
7628
+ if("string"!=typeof n||!n.trim())return"A repository connection needs the dockerfile to build, as a path inside the repository, for example mcp/server.Dockerfile"
7629
+ if(t(n))return"dockerfile is the path of a Dockerfile in this repository, for example mcp/server.Dockerfile, not its contents. To run a published image, the repository needs a Dockerfile that says FROM <the image>: have it written in the repository first, then give its path here."
7630
+ if(!r(n.trim()))return`dockerfile must be a path inside the repository, not "${n}"`
7604
7631
  if(void 0!==e.context){if("string"!=typeof e.context||!e.context.trim())return"context, when given, is a directory inside the repository"
7605
- if(!t(e.context.trim()))return`context must be a directory inside the repository, not "${e.context}"`}return null},exports.isPinnedPackage=function(e){const t=String(e??"").lastIndexOf("@")
7632
+ if(t(e.context))return"context is the path of a directory in this repository (the docker build context), for example mcp/, not a description. Leave it out to build from the repository root."
7633
+ if(!r(e.context.trim()))return`context must be a directory inside the repository, not "${e.context}"`}return null},exports.isPinnedPackage=function(e){const t=String(e??"").lastIndexOf("@")
7606
7634
  return!(t<=0)&&/^\d/.test(e.slice(t+1))},exports.Tt=["alchemy"],exports.x4=/^[a-z][a-z0-9-]{1,38}$/},34803(e,exports,t){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
7607
7635
  Object.defineProperty(exports,"__esModule",{value:!0}),exports.mimeFor=function(e){return o[n.default.extname(e).toLowerCase()]??"application/octet-stream"}
7608
7636
  const n=r(t(16928)),o={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".svg":"image/svg+xml",".pdf":"application/pdf",".html":"text/html; charset=utf-8",".htm":"text/html; charset=utf-8",".md":"text/markdown; charset=utf-8",".csv":"text/csv; charset=utf-8",".json":"application/json; charset=utf-8",".txt":"text/plain; charset=utf-8",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation",".zip":"application/zip",".gz":"application/gzip",".tgz":"application/gzip",".tar":"application/x-tar",".vtu":"application/xml",".vtk":"application/octet-stream",".msh":"text/plain; charset=utf-8"}},35510(e,exports,t){async function r(e,t){try{return{files:(await e.raw(["grep","-l","-e","^<<<<<<< ",t,"--","."])).split("\n").map(e=>e.trim()).filter(Boolean).map(e=>e.startsWith(`${t}:`)?e.slice(t.length+1):e),determined:!0}}catch(e){const t=String(e?.message??"")