alchemylab 1.4.12 → 1.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +16 -6
- package/dist/http-server.js +7 -6
- package/dist/index.js +7 -6
- package/dist/mcp-direct.js +7 -6
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -947,17 +947,17 @@ module.exports=require("winston")},5317(module){"use strict"
|
|
|
947
947
|
module.exports=require("child_process")},5419(e,exports,t){"use strict"
|
|
948
948
|
function r(e){return(0,o.join)((0,s.homedir)(),n.ALCHEMY_DIR_NAME,e?"opencode-dev":"opencode")}Object.defineProperty(exports,"__esModule",{value:!0}),exports.getGlobalConfigDir=r,exports.getOpencodeSpawnEnv=function(e,t){return{OPENCODE_CLIENT:"alchemy",OPENCODE_DATA_DIR:(0,o.join)(e,n.ALCHEMY_DIR_NAME,"opencode"),OPENCODE_CONFIG_DIR:r(t)}}
|
|
949
949
|
const s=t(857),o=t(6928),n=t(4139)},5607(e,exports,t){"use strict"
|
|
950
|
-
Object.defineProperty(exports,"__esModule",{value:!0}),exports.executeAction=async function(e,t,r){const s=
|
|
950
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.executeAction=async function(e,t,r){const s=y[e]
|
|
951
951
|
if(!s)return{success:!1,message:"Unknown action type: "+e,error:"No handler registered for action type: "+e}
|
|
952
|
-
try{return await s(t,r)}catch(t){const s=(0,
|
|
952
|
+
try{return await s(t,r)}catch(t){const s=(0,m.getErrorMessage)(t)
|
|
953
953
|
return r.logger.error("Action handler failed",{actionType:e,error:s}),{success:!1,message:"Action failed: "+s,error:s}}}
|
|
954
|
-
const r=t(6636),s=t(7453),o=t(5700),n=t(848),i=t(9735),a=t(7767),c=t(9266),l=t(6555),d=t(3614),u=t(4654),h=t(7078),g=t(
|
|
954
|
+
const r=t(6636),s=t(7453),o=t(5700),n=t(848),i=t(9735),a=t(7767),c=t(9266),l=t(6555),d=t(3614),u=t(4654),h=t(7078),g=t(7775),p=t(1405),m=t(8824),f=t(2272),y={revert_request:r.handleRevertRequestAction,"revert-request":r.handleRevertRequestAction,complete_request:s.handleCompleteRequestAction,"complete-request":s.handleCompleteRequestAction,"finalize-request":n.handleFinalizeRequestAction,"approve-request":i.handleApproveRequestAction,"approve-and-work-request":a.handleApproveAndWorkRequestAction,"restart-mcp":o.handleRestartMcpAction,"opencode-proxy":c.handleOpenCodeProxyAction,"run-tests":l.handleRunTestsAction,async"inject-prompt"(e,r){const{sessionId:s,message:o,kind:n,partPayload:i}=e
|
|
955
955
|
if(!s||!o)return{success:!1,message:"sessionId and message are required",error:"missing_params"}
|
|
956
956
|
const{getOpenCodeUrlFromConfig:a}=await Promise.resolve().then(t.t.bind(t,833,23)),c=a(r.projectPath)
|
|
957
957
|
if(!c)return{success:!1,message:"Cannot read OpenCode config",error:"no_opencode"}
|
|
958
|
-
try{const e=await fetch(`${c}/session/${s}/prompt_async`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({parts:[{type:"text",text:o,metadata:(0,
|
|
958
|
+
try{const e=await fetch(`${c}/session/${s}/prompt_async`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({parts:[{type:"text",text:o,metadata:(0,f.partMeta)(n??"inserted-prompt",i)}],...r.cachedDefaultModel?(()=>{const[e,...t]=r.cachedDefaultModel.split("/")
|
|
959
959
|
return{model:{providerID:e,modelID:t.join("/")}}})():{}}),signal:AbortSignal.timeout(1e4)})
|
|
960
|
-
return e.ok?{success:!0,message:"Prompt injected into session "+s}:{success:!1,message:"prompt_async failed: "+e.status,error:"prompt_failed"}}catch(e){return{success:!1,message:(0,
|
|
960
|
+
return e.ok?{success:!0,message:"Prompt injected into session "+s}:{success:!1,message:"prompt_async failed: "+e.status,error:"prompt_failed"}}catch(e){return{success:!1,message:(0,m.getErrorMessage)(e),error:"prompt_error"}}},"fork-filesystem":d.handleForkFilesystemAction,"prompt-and-wait":u.handlePromptAndWaitAction,"run-ab-prompt":u.handlePromptAndWaitAction,"spawn-auto-planner":h.handleSpawnAutoPlannerAction,"spawn-reviewer":g.handleSpawnReviewerAction,"start-building":p.handleStartBuildingAction}},5671(e,exports,t){"use strict"
|
|
961
961
|
function r(e){const[t,...r]=e.split("/")
|
|
962
962
|
return{provider:t||"anthropic",modelId:r.join("/")||e}}function s(e){const t={anthropic:!1,openai:!1}
|
|
963
963
|
try{const s=(0,a.join)(e,"opencode.json")
|
|
@@ -1394,7 +1394,17 @@ return{model:{providerID:e,modelID:r.join("/")}}})():{}})})
|
|
|
1394
1394
|
i.ok?n.info("Pushed notification to CLI session",{sessionId:f}):n.warn("Failed to push notification to CLI session",{status:i.status})}}catch(e){n.warn("Could not push notification to CLI session (may be offline)",{error:(0,r.getErrorMessage)(e)})}}catch(e){n.warn("Failed to notify target session, spawning work agent instead",{requestId:o,error:(0,r.getErrorMessage)(e)})}if(!p)try{const e=await(0,s.spawnActionAgent)({agent:"work",prompt:h,cwd:c,projectPath:c,projectId:a,title:`[${o}] ${d.title}`,requestId:o,parentSessionId:g,apiClient:i,logger:n,trackChildPid:l})
|
|
1395
1395
|
m=e.success,m?n.info("Spawned work agent for request",{requestId:o,sessionId:e.sessionId}):n.warn("Failed to spawn work agent",{requestId:o,error:e.error})}catch(e){n.warn("Failed to spawn work agent",{requestId:o,error:(0,r.getErrorMessage)(e)})}return n.info("Approve-and-work-request action completed",{requestId:o,notifiedSession:p,agentSpawned:m}),{success:!0,message:`Successfully approved request ${o}: ${d.title}${p?" \u2014 creating session notified":m?" \u2014 work agent spawned":""}`,data:{operationType:"approve-and-work",previousStatus:"pending_approval",newStatus:"open",notifiedSession:p,agentSpawned:m}}}catch(e){const t=(0,r.getErrorMessage)(e)
|
|
1396
1396
|
return n.error("approve-and-work-request action failed",{requestId:o,error:t}),{success:!1,message:"Failed to approve request: "+t,error:t}}}
|
|
1397
|
-
const r=t(8824),s=t(8148)},
|
|
1397
|
+
const r=t(8824),s=t(8148)},7775(e,exports,t){"use strict"
|
|
1398
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.REVIEWER_FOCUSES=void 0,exports.handleSpawnReviewerAction=async function(e,t){const{requestId:o,parentSessionId:n,focus:i}=e,{logger:a,apiClient:c,projectId:l,projectPath:d,trackChildPid:u}=t
|
|
1399
|
+
if(!o||!n||!i)return{success:!1,message:"spawn-reviewer requires requestId, parentSessionId, and focus",error:"Missing payload fields"}
|
|
1400
|
+
if("string"!=typeof(h=i)||!exports.REVIEWER_FOCUSES.includes(h))return{success:!1,message:"Invalid focus: "+i,error:"Invalid focus"}
|
|
1401
|
+
var h
|
|
1402
|
+
a.info("Starting spawn-reviewer action",{requestId:o,focus:i,parentSessionId:n})
|
|
1403
|
+
try{const e=function(e,t,r){return`[Session Context]\n- Request id: ${e}\n- Your focus: ${t}\n- Coder session to report to: ${r}\n\nYou are reviewing this request's diff with a single focus: **${t}**. Other dimensions are being reviewed in parallel by your peers \u2014 ignore them silently.\n\n1. Call \`request_diff\` to read the diff.\n2. Use \`read_files\` and \`search\` to gather context for any finding you intend to flag.\n3. Categorize each finding into must_fix / nice_to_have / out_of_scope per your agent instructions.\n4. Send ONE report via \`session_message_operations send\` with type "report", toSessionId "${r}", finish true, and the structured markdown summary.\n5. Exit. Do not send follow-ups.`}(o,i,n),t=`Reviewer (${i}) for ${o}`,s=await(0,r.spawnActionAgent)({agent:"reviewer",prompt:e,cwd:d,projectPath:d,projectId:l,title:t,requestId:o,parentSessionId:n,allowParallel:!0,apiClient:c,logger:a,trackChildPid:u})
|
|
1404
|
+
return s.success&&s.sessionId?{success:!0,message:`Reviewer spawned: ${i} for ${o}`,data:{sessionId:s.sessionId,pid:s.pid,focus:i}}:{success:!1,message:`Failed to spawn reviewer (${i}): ${s.error}`,error:s.error||"Spawn failed"}}catch(e){const t=(0,s.getErrorMessage)(e)
|
|
1405
|
+
return a.error("spawn-reviewer action failed",{requestId:o,focus:i,error:t}),{success:!1,message:`Failed to spawn reviewer (${i}): ${t}`,error:t}}}
|
|
1406
|
+
const r=t(8148),s=t(8824)
|
|
1407
|
+
exports.REVIEWER_FOCUSES=["REUSE","QUALITY","EFFICIENCY"]},7904(e,exports){"use strict"
|
|
1398
1408
|
Object.defineProperty(exports,"__esModule",{value:!0}),exports.REPORT_STATUS_EMOJI=void 0,exports.formatReportNotification=function(e){const{messageCode:t,status:r,summary:s,details:o,fromSessionId:n,senderAgent:i}=e,a=[`${exports.REPORT_STATUS_EMOJI[r]||"\u{1f4cb}"} **Report \u2014 ${r}**`]
|
|
1399
1409
|
return t&&a.push("**Report Code:** "+t),i&&a.push(n?`from: ${i} (${n})`:"from: "+i),a.push("",s||"Task completed"),o&&a.push("",o),t&&a.push("",`Use \`session_message_operations\` with \`reply\` operation and message code \`${t}\` to acknowledge.`),a.join("\n")},exports.REPORT_STATUS_EMOJI={success:"\u2705",partial:"\u26a0\ufe0f",failure:"\u274c",blocked:"\u{1f6ab}"}},7960(e,exports){"use strict"
|
|
1400
1410
|
function t(){const e=process.argv[1]||""
|
package/dist/http-server.js
CHANGED
|
@@ -1385,11 +1385,12 @@ const o=process.config||{},s=o.commands||[]
|
|
|
1385
1385
|
let a=`## ${process.name}\n`
|
|
1386
1386
|
process.description&&(a+=process.description+"\n"),process.scope&&(a+=`**Scope:** \`${process.scope}\`\n`),a+=`**Status:** ${process.isActive?"Active":"Inactive"}\n\n`,o.setup?.length&&(a+=`### Setup\n${o.setup.map((e=>`\`\`\`\n${e}\n\`\`\``)).join("\n")}\n\n`),a+=`### Test Commands (${s.length})\n`
|
|
1387
1387
|
for(let e=0;e<s.length;e++){const t=s[e]
|
|
1388
|
-
a+=`\n**${e+1}. ${t.name}**${t.required?" \u2014 REQUIRED":" \u2014 optional"}\n`,a+=` Command: \`${t.command}\`\n`,t.timeout&&(a+=` Timeout: ${t.timeout}s\n`)}return Array.isArray(o.fingerprint)&&o.fingerprint.length>0&&(a+=`\n### Fingerprint Files\n${o.fingerprint.map((e=>`- \`${e}\``)).join("\n")}\n`),"number"==typeof o.poolSize&&(a+=`\n**Pool size:** ${o.poolSize}\n`),i({success:!0}),{content:[{type:"text",text:a}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to get test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessCreate=async function(e,
|
|
1389
|
-
try{const
|
|
1390
|
-
void 0!==e.fingerprint&&(
|
|
1391
|
-
const
|
|
1392
|
-
|
|
1388
|
+
a+=`\n**${e+1}. ${t.name}**${t.required?" \u2014 REQUIRED":" \u2014 optional"}\n`,a+=` Command: \`${t.command}\`\n`,t.timeout&&(a+=` Timeout: ${t.timeout}s\n`)}return Array.isArray(o.fingerprint)&&o.fingerprint.length>0&&(a+=`\n### Fingerprint Files\n${o.fingerprint.map((e=>`- \`${e}\``)).join("\n")}\n`),"number"==typeof o.poolSize&&(a+=`\n**Pool size:** ${o.poolSize}\n`),i({success:!0}),{content:[{type:"text",text:a}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to get test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessCreate=async function(e,n,o,s,i){const a=i.startTimer("tool_execution_time")
|
|
1389
|
+
try{const i={setup:e.setup||[],commands:e.commands.map((e=>({name:e.name,command:e.command,required:!1!==e.required,timeout:e.timeout||300})))}
|
|
1390
|
+
void 0!==e.fingerprint&&(i.fingerprint=e.fingerprint),void 0!==e.poolSize&&(i.poolSize=e.poolSize)
|
|
1391
|
+
const c=await o.proxyPost(`/api/projects/${n.projectId}/test-processes`,{name:e.name,description:e.description,scope:e.scope,config:i,createdBy:"test-architect"}),process=c?.data||c
|
|
1392
|
+
try{const{sessionIdentity:e}=await Promise.resolve().then(t.bind(t,6688)),r=e.getIdentity()
|
|
1393
|
+
r?.sessionId&&process?.id&&await o.proxyPost(`/api/projects/${n.projectId}/session-test-process-associations`,{opencodeSessionId:r.sessionId,testProcessId:process.id})}catch(e){s.warn("Failed to write session-test-process association",{error:(0,r.getErrorMessage)(e)})}return a({success:!0}),{content:[{type:"text",text:`\u2705 Created test process **${process.name}** (${process.id}) with ${i.commands.length} test commands.${e.scope?`\nScope: \`${e.scope}\``:""}\n\nThe process is now active and will run when requests are completed.`}]}}catch(e){return a({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to create test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessUpdate=async function(e,t,n,o,s){const i=s.startTimer("tool_execution_time")
|
|
1393
1394
|
try{const r={}
|
|
1394
1395
|
if(void 0!==e.name&&(r.name=e.name),void 0!==e.description&&(r.description=e.description),void 0!==e.scope&&(r.scope=e.scope),void 0!==e.isActive&&(r.isActive=e.isActive),void 0!==e.commands||void 0!==e.setup||void 0!==e.fingerprint||void 0!==e.poolSize){const o=await n.proxyGet(`/api/projects/${t.projectId}/test-processes/${e.processId}`),s=o?.data||o,i=s?.config||{},a={setup:e.setup??i.setup??[],commands:e.commands?e.commands.map((e=>({name:e.name,command:e.command,required:!1!==e.required,timeout:e.timeout||300}))):i.commands??[]}
|
|
1395
1396
|
void 0!==e.fingerprint?a.fingerprint=e.fingerprint:void 0!==i.fingerprint&&(a.fingerprint=i.fingerprint),void 0!==e.poolSize?a.poolSize=e.poolSize:void 0!==i.poolSize&&(a.poolSize=i.poolSize),void 0!==i.verifyAcceptanceCriteria&&(a.verifyAcceptanceCriteria=i.verifyAcceptanceCriteria),r.config=a}const o=await n.proxyPatch(`/api/projects/${t.projectId}/test-processes/${e.processId}`,r),process=o?.data||o
|
|
@@ -3337,7 +3338,7 @@ return m({success:!1,error:"status_transition_failed"}),{content:[{type:"text",t
|
|
|
3337
3338
|
try{C=await f.getRequest(n)}catch(e){const t=(0,s.getErrorMessage)(e)
|
|
3338
3339
|
return m({success:!1,error:"fetch_request_failed"}),{content:[{type:"text",text:"Failed to fetch request criteria: "+t}],isError:!0}}const _=C?.acceptanceCriteria||[]
|
|
3339
3340
|
if(m({success:!0}),w){const e=g.completionMode
|
|
3340
|
-
return{content:[{type:"text",text:`Request ${n} moved to ready_for_review. ${"ask-me"===e?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip).":`Tests are running automatically in the background (${e} mode).
|
|
3341
|
+
return{content:[{type:"text",text:`Request ${n} moved to ready_for_review. ${"ask-me"===e?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip). Stop here; you will receive a report when testing finishes.":`Tests are running automatically in the background (${e} mode). Stop here; a tester subagent will run the test commands and post a report back to you when done.`}\n\n## When the report arrives\n- **Passed** \u2014 call \`merge\` with verification evidence for each acceptance criterion to finalize the request.\n- **Failed** \u2014 fix the issues and call \`complete\` again.\n\nDo NOT call merge, finalize, or any other tool BEFORE the report arrives \u2014 stop here and wait.`}]}}if(I)return{content:[{type:"text",text:`Request ${n} submitted for human review.${g.testsSkipped&&l?`\n\n_Tests skipped: ${l}_`:""}\n\nThe project is set to manual-review \u2014 a person will approve and merge from the UI. Do NOT call merge yourself.`}]}
|
|
3341
3342
|
const E=k?`\n\n_Skipped re-running tests: ${k}._\n`:"",S=y?`\n\n_No test processes are configured for this project; ${g.completionMode} mode is being treated as auto-merge._\n`:""
|
|
3342
3343
|
return 0===_.length?{content:[{type:"text",text:`Request ${n} is ready. ${E}${S}No acceptance criteria defined \u2014 call merge directly.`}]}:{content:[{type:"text",text:`Request ${n} completion started (${v}).${E}${S}\n\n## Next Step: Verify & Merge\n\n${(0,i.formatVerifyInstructions)(_)}\n\nUse the merge operation with your verification evidence to merge to main.`}]}}catch(r){let s="An unexpected error occurred",i=""
|
|
3343
3344
|
r instanceof n.ZodError?(s="Validation error",i=r.errors.map((e=>`${e.path.join(".")}: ${e.message}`)).join(", ")):r instanceof Error?(s=r.message,i=r.stack||""):i=r+"",p.error("Complete request failed",{error:s,details:i})
|
package/dist/index.js
CHANGED
|
@@ -1387,11 +1387,12 @@ const o=process.config||{},s=o.commands||[]
|
|
|
1387
1387
|
let a=`## ${process.name}\n`
|
|
1388
1388
|
process.description&&(a+=process.description+"\n"),process.scope&&(a+=`**Scope:** \`${process.scope}\`\n`),a+=`**Status:** ${process.isActive?"Active":"Inactive"}\n\n`,o.setup?.length&&(a+=`### Setup\n${o.setup.map((e=>`\`\`\`\n${e}\n\`\`\``)).join("\n")}\n\n`),a+=`### Test Commands (${s.length})\n`
|
|
1389
1389
|
for(let e=0;e<s.length;e++){const t=s[e]
|
|
1390
|
-
a+=`\n**${e+1}. ${t.name}**${t.required?" \u2014 REQUIRED":" \u2014 optional"}\n`,a+=` Command: \`${t.command}\`\n`,t.timeout&&(a+=` Timeout: ${t.timeout}s\n`)}return Array.isArray(o.fingerprint)&&o.fingerprint.length>0&&(a+=`\n### Fingerprint Files\n${o.fingerprint.map((e=>`- \`${e}\``)).join("\n")}\n`),"number"==typeof o.poolSize&&(a+=`\n**Pool size:** ${o.poolSize}\n`),i({success:!0}),{content:[{type:"text",text:a}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to get test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessCreate=async function(e,
|
|
1391
|
-
try{const
|
|
1392
|
-
void 0!==e.fingerprint&&(
|
|
1393
|
-
const
|
|
1394
|
-
|
|
1390
|
+
a+=`\n**${e+1}. ${t.name}**${t.required?" \u2014 REQUIRED":" \u2014 optional"}\n`,a+=` Command: \`${t.command}\`\n`,t.timeout&&(a+=` Timeout: ${t.timeout}s\n`)}return Array.isArray(o.fingerprint)&&o.fingerprint.length>0&&(a+=`\n### Fingerprint Files\n${o.fingerprint.map((e=>`- \`${e}\``)).join("\n")}\n`),"number"==typeof o.poolSize&&(a+=`\n**Pool size:** ${o.poolSize}\n`),i({success:!0}),{content:[{type:"text",text:a}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to get test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessCreate=async function(e,n,o,s,i){const a=i.startTimer("tool_execution_time")
|
|
1391
|
+
try{const i={setup:e.setup||[],commands:e.commands.map((e=>({name:e.name,command:e.command,required:!1!==e.required,timeout:e.timeout||300})))}
|
|
1392
|
+
void 0!==e.fingerprint&&(i.fingerprint=e.fingerprint),void 0!==e.poolSize&&(i.poolSize=e.poolSize)
|
|
1393
|
+
const c=await o.proxyPost(`/api/projects/${n.projectId}/test-processes`,{name:e.name,description:e.description,scope:e.scope,config:i,createdBy:"test-architect"}),process=c?.data||c
|
|
1394
|
+
try{const{sessionIdentity:e}=await Promise.resolve().then(t.bind(t,6688)),r=e.getIdentity()
|
|
1395
|
+
r?.sessionId&&process?.id&&await o.proxyPost(`/api/projects/${n.projectId}/session-test-process-associations`,{opencodeSessionId:r.sessionId,testProcessId:process.id})}catch(e){s.warn("Failed to write session-test-process association",{error:(0,r.getErrorMessage)(e)})}return a({success:!0}),{content:[{type:"text",text:`\u2705 Created test process **${process.name}** (${process.id}) with ${i.commands.length} test commands.${e.scope?`\nScope: \`${e.scope}\``:""}\n\nThe process is now active and will run when requests are completed.`}]}}catch(e){return a({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to create test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessUpdate=async function(e,t,n,o,s){const i=s.startTimer("tool_execution_time")
|
|
1395
1396
|
try{const r={}
|
|
1396
1397
|
if(void 0!==e.name&&(r.name=e.name),void 0!==e.description&&(r.description=e.description),void 0!==e.scope&&(r.scope=e.scope),void 0!==e.isActive&&(r.isActive=e.isActive),void 0!==e.commands||void 0!==e.setup||void 0!==e.fingerprint||void 0!==e.poolSize){const o=await n.proxyGet(`/api/projects/${t.projectId}/test-processes/${e.processId}`),s=o?.data||o,i=s?.config||{},a={setup:e.setup??i.setup??[],commands:e.commands?e.commands.map((e=>({name:e.name,command:e.command,required:!1!==e.required,timeout:e.timeout||300}))):i.commands??[]}
|
|
1397
1398
|
void 0!==e.fingerprint?a.fingerprint=e.fingerprint:void 0!==i.fingerprint&&(a.fingerprint=i.fingerprint),void 0!==e.poolSize?a.poolSize=e.poolSize:void 0!==i.poolSize&&(a.poolSize=i.poolSize),void 0!==i.verifyAcceptanceCriteria&&(a.verifyAcceptanceCriteria=i.verifyAcceptanceCriteria),r.config=a}const o=await n.proxyPatch(`/api/projects/${t.projectId}/test-processes/${e.processId}`,r),process=o?.data||o
|
|
@@ -3346,7 +3347,7 @@ return g({success:!1,error:"status_transition_failed"}),{content:[{type:"text",t
|
|
|
3346
3347
|
try{C=await f.getRequest(n)}catch(e){const t=(0,s.getErrorMessage)(e)
|
|
3347
3348
|
return g({success:!1,error:"fetch_request_failed"}),{content:[{type:"text",text:"Failed to fetch request criteria: "+t}],isError:!0}}const _=C?.acceptanceCriteria||[]
|
|
3348
3349
|
if(g({success:!0}),w){const e=m.completionMode
|
|
3349
|
-
return{content:[{type:"text",text:`Request ${n} moved to ready_for_review. ${"ask-me"===e?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip).":`Tests are running automatically in the background (${e} mode).
|
|
3350
|
+
return{content:[{type:"text",text:`Request ${n} moved to ready_for_review. ${"ask-me"===e?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip). Stop here; you will receive a report when testing finishes.":`Tests are running automatically in the background (${e} mode). Stop here; a tester subagent will run the test commands and post a report back to you when done.`}\n\n## When the report arrives\n- **Passed** \u2014 call \`merge\` with verification evidence for each acceptance criterion to finalize the request.\n- **Failed** \u2014 fix the issues and call \`complete\` again.\n\nDo NOT call merge, finalize, or any other tool BEFORE the report arrives \u2014 stop here and wait.`}]}}if(b)return{content:[{type:"text",text:`Request ${n} submitted for human review.${m.testsSkipped&&l?`\n\n_Tests skipped: ${l}_`:""}\n\nThe project is set to manual-review \u2014 a person will approve and merge from the UI. Do NOT call merge yourself.`}]}
|
|
3350
3351
|
const E=k?`\n\n_Skipped re-running tests: ${k}._\n`:"",S=y?`\n\n_No test processes are configured for this project; ${m.completionMode} mode is being treated as auto-merge._\n`:""
|
|
3351
3352
|
return 0===_.length?{content:[{type:"text",text:`Request ${n} is ready. ${E}${S}No acceptance criteria defined \u2014 call merge directly.`}]}:{content:[{type:"text",text:`Request ${n} completion started (${v}).${E}${S}\n\n## Next Step: Verify & Merge\n\n${(0,i.formatVerifyInstructions)(_)}\n\nUse the merge operation with your verification evidence to merge to main.`}]}}catch(r){let s="An unexpected error occurred",i=""
|
|
3352
3353
|
r instanceof n.ZodError?(s="Validation error",i=r.errors.map((e=>`${e.path.join(".")}: ${e.message}`)).join(", ")):r instanceof Error?(s=r.message,i=r.stack||""):i=r+"",p.error("Complete request failed",{error:s,details:i})
|
package/dist/mcp-direct.js
CHANGED
|
@@ -1284,11 +1284,12 @@ const s=process.config||{},o=s.commands||[]
|
|
|
1284
1284
|
let a=`## ${process.name}\n`
|
|
1285
1285
|
process.description&&(a+=process.description+"\n"),process.scope&&(a+=`**Scope:** \`${process.scope}\`\n`),a+=`**Status:** ${process.isActive?"Active":"Inactive"}\n\n`,s.setup?.length&&(a+=`### Setup\n${s.setup.map((e=>`\`\`\`\n${e}\n\`\`\``)).join("\n")}\n\n`),a+=`### Test Commands (${o.length})\n`
|
|
1286
1286
|
for(let e=0;e<o.length;e++){const t=o[e]
|
|
1287
|
-
a+=`\n**${e+1}. ${t.name}**${t.required?" \u2014 REQUIRED":" \u2014 optional"}\n`,a+=` Command: \`${t.command}\`\n`,t.timeout&&(a+=` Timeout: ${t.timeout}s\n`)}return Array.isArray(s.fingerprint)&&s.fingerprint.length>0&&(a+=`\n### Fingerprint Files\n${s.fingerprint.map((e=>`- \`${e}\``)).join("\n")}\n`),"number"==typeof s.poolSize&&(a+=`\n**Pool size:** ${s.poolSize}\n`),i({success:!0}),{content:[{type:"text",text:a}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to get test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessCreate=async function(e,
|
|
1288
|
-
try{const
|
|
1289
|
-
void 0!==e.fingerprint&&(
|
|
1290
|
-
const
|
|
1291
|
-
|
|
1287
|
+
a+=`\n**${e+1}. ${t.name}**${t.required?" \u2014 REQUIRED":" \u2014 optional"}\n`,a+=` Command: \`${t.command}\`\n`,t.timeout&&(a+=` Timeout: ${t.timeout}s\n`)}return Array.isArray(s.fingerprint)&&s.fingerprint.length>0&&(a+=`\n### Fingerprint Files\n${s.fingerprint.map((e=>`- \`${e}\``)).join("\n")}\n`),"number"==typeof s.poolSize&&(a+=`\n**Pool size:** ${s.poolSize}\n`),i({success:!0}),{content:[{type:"text",text:a}]}}catch(e){return i({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to get test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessCreate=async function(e,n,s,o,i){const a=i.startTimer("tool_execution_time")
|
|
1288
|
+
try{const i={setup:e.setup||[],commands:e.commands.map((e=>({name:e.name,command:e.command,required:!1!==e.required,timeout:e.timeout||300})))}
|
|
1289
|
+
void 0!==e.fingerprint&&(i.fingerprint=e.fingerprint),void 0!==e.poolSize&&(i.poolSize=e.poolSize)
|
|
1290
|
+
const c=await s.proxyPost(`/api/projects/${n.projectId}/test-processes`,{name:e.name,description:e.description,scope:e.scope,config:i,createdBy:"test-architect"}),process=c?.data||c
|
|
1291
|
+
try{const{sessionIdentity:e}=await Promise.resolve().then(t.bind(t,6688)),r=e.getIdentity()
|
|
1292
|
+
r?.sessionId&&process?.id&&await s.proxyPost(`/api/projects/${n.projectId}/session-test-process-associations`,{opencodeSessionId:r.sessionId,testProcessId:process.id})}catch(e){o.warn("Failed to write session-test-process association",{error:(0,r.getErrorMessage)(e)})}return a({success:!0}),{content:[{type:"text",text:`\u2705 Created test process **${process.name}** (${process.id}) with ${i.commands.length} test commands.${e.scope?`\nScope: \`${e.scope}\``:""}\n\nThe process is now active and will run when requests are completed.`}]}}catch(e){return a({success:!1,error:"api_error"}),{content:[{type:"text",text:"Failed to create test process: "+(0,r.getErrorMessage)(e)}],isError:!0}}},exports.handleTestingProcessUpdate=async function(e,t,n,s,o){const i=o.startTimer("tool_execution_time")
|
|
1292
1293
|
try{const r={}
|
|
1293
1294
|
if(void 0!==e.name&&(r.name=e.name),void 0!==e.description&&(r.description=e.description),void 0!==e.scope&&(r.scope=e.scope),void 0!==e.isActive&&(r.isActive=e.isActive),void 0!==e.commands||void 0!==e.setup||void 0!==e.fingerprint||void 0!==e.poolSize){const s=await n.proxyGet(`/api/projects/${t.projectId}/test-processes/${e.processId}`),o=s?.data||s,i=o?.config||{},a={setup:e.setup??i.setup??[],commands:e.commands?e.commands.map((e=>({name:e.name,command:e.command,required:!1!==e.required,timeout:e.timeout||300}))):i.commands??[]}
|
|
1294
1295
|
void 0!==e.fingerprint?a.fingerprint=e.fingerprint:void 0!==i.fingerprint&&(a.fingerprint=i.fingerprint),void 0!==e.poolSize?a.poolSize=e.poolSize:void 0!==i.poolSize&&(a.poolSize=i.poolSize),void 0!==i.verifyAcceptanceCriteria&&(a.verifyAcceptanceCriteria=i.verifyAcceptanceCriteria),r.config=a}const s=await n.proxyPatch(`/api/projects/${t.projectId}/test-processes/${e.processId}`,r),process=s?.data||s
|
|
@@ -3113,7 +3114,7 @@ return m({success:!1,error:"status_transition_failed"}),{content:[{type:"text",t
|
|
|
3113
3114
|
try{C=await f.getRequest(n)}catch(e){const t=(0,o.getErrorMessage)(e)
|
|
3114
3115
|
return m({success:!1,error:"fetch_request_failed"}),{content:[{type:"text",text:"Failed to fetch request criteria: "+t}],isError:!0}}const _=C?.acceptanceCriteria||[]
|
|
3115
3116
|
if(m({success:!0}),w){const e=g.completionMode
|
|
3116
|
-
return{content:[{type:"text",text:`Request ${n} moved to ready_for_review. ${"ask-me"===e?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip).":`Tests are running automatically in the background (${e} mode).
|
|
3117
|
+
return{content:[{type:"text",text:`Request ${n} moved to ready_for_review. ${"ask-me"===e?"A notification has been created asking the user to choose how to handle testing (auto-test, interactive-test, or skip). Stop here; you will receive a report when testing finishes.":`Tests are running automatically in the background (${e} mode). Stop here; a tester subagent will run the test commands and post a report back to you when done.`}\n\n## When the report arrives\n- **Passed** \u2014 call \`merge\` with verification evidence for each acceptance criterion to finalize the request.\n- **Failed** \u2014 fix the issues and call \`complete\` again.\n\nDo NOT call merge, finalize, or any other tool BEFORE the report arrives \u2014 stop here and wait.`}]}}if(b)return{content:[{type:"text",text:`Request ${n} submitted for human review.${g.testsSkipped&&l?`\n\n_Tests skipped: ${l}_`:""}\n\nThe project is set to manual-review \u2014 a person will approve and merge from the UI. Do NOT call merge yourself.`}]}
|
|
3117
3118
|
const E=k?`\n\n_Skipped re-running tests: ${k}._\n`:"",S=y?`\n\n_No test processes are configured for this project; ${g.completionMode} mode is being treated as auto-merge._\n`:""
|
|
3118
3119
|
return 0===_.length?{content:[{type:"text",text:`Request ${n} is ready. ${E}${S}No acceptance criteria defined \u2014 call merge directly.`}]}:{content:[{type:"text",text:`Request ${n} completion started (${v}).${E}${S}\n\n## Next Step: Verify & Merge\n\n${(0,i.formatVerifyInstructions)(_)}\n\nUse the merge operation with your verification evidence to merge to main.`}]}}catch(r){let o="An unexpected error occurred",i=""
|
|
3119
3120
|
r instanceof n.ZodError?(o="Validation error",i=r.errors.map((e=>`${e.path.join(".")}: ${e.message}`)).join(", ")):r instanceof Error?(o=r.message,i=r.stack||""):i=r+"",p.error("Complete request failed",{error:o,details:i})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alchemylab",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.13",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "AlchemyLab - agentic coding IDEm",
|
|
6
6
|
"author": "Testfire Software",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"ws": "^8.14.2",
|
|
50
50
|
"zod": "^3.22.4",
|
|
51
51
|
"zod-to-json-schema": "^3.22.3",
|
|
52
|
-
"alchemylab-opencode": "^1.0.
|
|
52
|
+
"alchemylab-opencode": "^1.0.17"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/chai": "^4.3.5",
|