alchemylab 2.0.2 → 2.1.1
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/111.js +14 -0
- package/dist/24.js +37 -0
- package/dist/293.js +58 -0
- package/dist/{491.js → 356.js} +11 -11
- package/dist/414.js +18 -0
- package/dist/478.js +89 -0
- package/dist/{636.js → 579.js} +7 -7
- package/dist/{565.js → 60.js} +8 -8
- package/dist/729.js +46 -88
- package/dist/{129.js → 776.js} +2 -2
- package/dist/{237.js → 800.js} +3 -3
- package/dist/816.js +3 -0
- package/dist/939.js +17 -0
- package/dist/{554.js → 991.js} +12 -12
- package/dist/{301.js → 994.js} +23 -23
- package/dist/cli.js +7423 -7151
- package/dist/document-textconv.js +307 -265
- package/dist/http-server.js +7530 -7524
- package/dist/index.js +7642 -7636
- package/dist/mcp-direct.js +7527 -7521
- package/dist/plugins/hooks/plugin.js +1 -1
- package/dist/plugins/system-logger.js +1 -1
- package/package.json +5 -2
- package/dist/19.js +0 -244
- package/dist/380.js +0 -17
- package/dist/403.js +0 -4
- package/dist/540.js +0 -56
- package/dist/603.js +0 -18
- package/dist/674.js +0 -15
- package/dist/796.js +0 -47
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as t from"path";import{join as e}from"path";import{readFileSync as n,existsSync as o}from"fs";const a=2e5;function r(t,e,n){if(e.length<=a)return null;const o=(e.length/1048576).toFixed(1);return[`[AlchemyLab did not pass this result on: ${e.length.toLocaleString()} characters (about ${o} MB).]`,"",`"${t}" returned more than fits usefully in context, so it was held back rather than`,"filling the window. The first part of it was:","",e.slice(0,2e3),"","[...held back...]","",n?`The whole result is stored: ${n}\nRead the part you need with \`result_inspect\` (operation "read", that address, plus a line range or \`find\`), or ask this connection for a summary or a narrower query.`:"Ask this connection for a path, a summary, or a narrower query instead of the whole result."].join("\n")}let s=null,i=null;function l(t,e){fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}).catch(
|
|
1
|
+
import*as t from"path";import{join as e}from"path";import{readFileSync as n,existsSync as o}from"fs";const a=2e5;function r(t,e,n){if(e.length<=a)return null;const o=(e.length/1048576).toFixed(1);return[`[AlchemyLab did not pass this result on: ${e.length.toLocaleString()} characters (about ${o} MB).]`,"",`"${t}" returned more than fits usefully in context, so it was held back rather than`,"filling the window. The first part of it was:","",e.slice(0,2e3),"","[...held back...]","",n?`The whole result is stored: ${n}\nRead the part you need with \`result_inspect\` (operation "read", that address, plus a line range or \`find\`), or ask this connection for a summary or a narrower query.`:"Ask this connection for a path, a summary, or a narrower query instead of the whole result."].join("\n")}let s=null,i=null;function l(t,e){fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}).catch(e=>{console.warn("[hooks-plugin] hook event delivery failed",t,e instanceof Error?e.message:String(e))})}async function c(t,e){try{await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),signal:AbortSignal.timeout(3e4)})}catch(e){e instanceof Error&&"TimeoutError"===e.name&&console.warn(`[hooks-plugin] after-event POST to ${t} aborted after 30000ms; blocking hooks may not have run`)}}let u=null;async function p(t){if(u&&Date.now()-u.at<6e4)return u.names;try{const e=await fetch(`${t}/api/mcp/namespaces`,{signal:AbortSignal.timeout(5e3)}),n=await e.json(),o=n?.data?.namespaces??[];return u={at:Date.now(),names:Array.isArray(o)?o:[]},u.names}catch{return u={at:Date.now(),names:u?.names??[]},u.names}}const h=new Set(["read","write","edit","patch","multiedit","apply_patch","bash","grep","glob","list","ls","todowrite","todoread","webfetch","websearch","task","skill","invalid"]);function f(t,e){return e.some(e=>t.startsWith(`${e}_`)&&t.length>e.length+1)}async function d(t,e){return!!f(e,await p(t))||!e.startsWith("alchemy_")&&!h.has(e)&&(u=null,f(e,await p(t)))}const y=[1,Number.MAX_SAFE_INTEGER];function m(t){return(Array.isArray(t?.operations)?t.operations:[]).filter(t=>"string"==typeof t?.path&&t.path).map(t=>({path:t.path}))}const g=(()=>{const t={kind:"edit",files:(t,e)=>function(t,e){const n=new Set;"string"==typeof t?.filePath&&n.add(t.filePath);for(const t of Array.isArray(e?.files)?e.files:[]){const e=t?.movePath??t?.filePath;"string"==typeof e&&"delete"!==t?.type&&n.add(e)}return[...n].map(t=>({path:t}))}(t,e)},e={kind:"edit",files:m};return{read:{kind:"read",files:t=>{if("string"!=typeof t?.filePath)return[];const e=Number(t.offset)>=1?Math.floor(Number(t.offset)):1,n=Number(t.limit)>=1?Math.floor(Number(t.limit)):2e3;return[{path:t.filePath,lines:[e,e+n-1]}]}},edit:t,write:t,multiedit:t,patch:t,apply_patch:t,alchemy_read_files:{kind:"read",files:t=>(Array.isArray(t?.paths)?t.paths:[]).filter(t=>"string"==typeof t?.path&&t.path).map(t=>{if(void 0!==t.lines){const e=function(t){const e=/^\s*(\d+)\s*(?:-\s*(\d+)\s*)?$/.exec("string"==typeof t?t:"");if(!e)return null;const n=Number(e[1]),o=void 0===e[2]?n:Number(e[2]);return n>=1&&o>=n?[n,o]:null}(t.lines);return e?{path:t.path,lines:e}:{path:t.path}}return t.symbol?{path:t.path}:{path:t.path,lines:y}})},alchemy_write_file:{kind:"edit",files:t=>"string"==typeof t?.path&&t.path?[{path:t.path}]:[]},alchemy_replace_in_files:e,alchemy_replace_strings:e,alchemy_replace_lines:e,alchemy_insert_lines:e,alchemy_modify_file:e}})();function w(t,e,n){const o=g[t];if(!o)return null;const a=new Set,r=o.files(e??{},n).filter(t=>!a.has(t.path)&&(a.add(t.path),!0));return r.length>0?{kind:o.kind,files:r}:null}function b(t,e){if("string"==typeof t?.output)return void(t.output+=`\n\n${e}`);const n=Array.isArray(t?.content)?t.content:null;if(!n||t.isError)return;const o=n.find(t=>"text"===t?.type&&"string"==typeof t.text);o?o.text+=`\n\n${e}`:n.push({type:"text",text:e})}export default async({directory:u})=>{const p=u||process.cwd();if(s===p&&i)return i;s=p;const h=function(t){try{const a=e(t,".alchemy_lab","action-server.json");if(!o(a))return 3456;const r=JSON.parse(n(a,"utf-8"));if("number"==typeof r.port&&r.port>0&&r.port<65536)return r.port}catch{}return 3456}(p),f=`http://localhost:${h}`;!async function(t,e,n){try{const o=await fetch(`http://localhost:${e}/health`,{signal:AbortSignal.timeout(1500)});if(!o.ok)return!1;const a=await o.json(),r="string"==typeof a?.projectPath?a.projectPath:"",s=!!r&&(r===t||r.endsWith(t)||t.endsWith(r));return s||n?.(`[alchemy hooks] port ${e} serves ${r||"an unknown project"}, not ${t}: hooks would fire into the wrong project`),s}catch{return n?.(`[alchemy hooks] nothing answered /health on port ${e}: hook events will not be delivered`),!1}}(p,h,t=>console.error(t));const y=`${f}/api/hook-event`,m=`${f}/api/tool-event`,g={"tool.execute.before":async(e,n)=>{const o=e?.tool||e?.name;if(!o)return;const a=e?.args||e?.input||{},r=e?.sessionID||"";"bash"===o&&n?.args&&"object"==typeof n.args&&await async function(e,n,o,a){const r="string"==typeof a.workdir&&a.workdir.trim()?a.workdir.trim():".";if(function(e,n){const o=t.resolve(e),a=t.resolve(o,n);if(a!==o&&!a.startsWith(o+t.sep))return!1;const r=t.join(o,".alchemy_lab");return!(a===r||a.startsWith(r+t.sep))}(n,r))try{const s=await fetch(`${e}/api/session-workdir?sessionId=${encodeURIComponent(o)}`,{signal:AbortSignal.timeout(5e3)}),i=s.ok?await s.json():null,l=i?.data?.workdir;if("string"!=typeof l||!l)return;const c=t.relative(t.resolve(n),t.resolve(n,r));a.workdir=c&&!c.startsWith("..")?t.join(l,c):l}catch{}}(f,p,r,n.args),await d(f,o)&&await async function(t,e,n,o,a){let r;try{const s=await fetch(`${t}/api/mcp/gate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({toolName:e,sessionId:n,args:o,callId:a}),signal:AbortSignal.timeout(66e4)}),i=await s.json();if(r=i?.data,!s.ok||!r)throw new Error(i?.error||`gate returned HTTP ${s.status}`)}catch(t){const n=t instanceof Error?t.message:String(t);throw console.warn("[hooks-plugin] MCP gate unreachable, refusing the call",e,n),new Error(`${e} was not run: its approval gate could not be reached (${n}).`)}if(!r.allow)throw new Error(`${e} was not run: ${r.reason}.`)}(f,o,r,a,e?.callID||""),l(m,{toolName:o,sessionId:r,input:a,timing:"before"})},"tool.execute.after":async(t,e)=>{const n=t?.tool||t?.name;if(!n)return;const o=e?w(String(n),t?.args,e.metadata):null;if(o){const n=await async function(t,e,n){if(!e)return null;try{const o=await fetch(`${t}/api/parallel-note`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sessionId:e,tool:n.kind,files:n.files}),signal:AbortSignal.timeout(4e3)});if(!o.ok)return null;const a=await o.json();return"string"==typeof a?.data?.note&&a.data.note?a.data.note:null}catch{return null}}(f,t?.sessionID||"",o);n&&b(e,n)}const s=e?.content?.[0]?.text;if("string"==typeof s&&s.length>a){const o=await async function(t,e,n,o){try{const a=await fetch(`${t}/api/results/spill`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:n,toolName:e,...o?{callId:o}:{}}),signal:AbortSignal.timeout(3e4)});if(!a.ok)return;const r=await a.json();return r?.data?.address??void 0}catch{return}}(f,String(n),s,t?.callID),a=r(String(n),s,o);if(a)return e.content[0].text=a,void await c(m,{toolName:n,sessionId:t?.sessionID||"",input:t?.args||t?.input||{},output:a,timing:"after",...t?.callID?{callId:t.callID}:{}})}var i;s?await c(m,{toolName:n,sessionId:t?.sessionID||"",input:t?.args||t?.input||{},output:(i=s,i.length<=8192?i:i.slice(0,6144)+"\n...[truncated]...\n"+i.slice(-2048)),timing:"after",callId:t?.callID||""}):t?.callID&&await d(f,n)&&await c(m,{toolName:n,sessionId:t?.sessionID||"",input:t?.args||t?.input||{},timing:"after",callId:t.callID})},event:async({event:t})=>{switch(t.type){case"session.idle":{const a=t.properties.sessionID||"",{output:r,lastMessageId:s}=await async function(t,a){try{const r=e(a,".alchemy_lab","opencode.json");if(!o(r))return{output:""};const s=JSON.parse(n(r,"utf8")),i=s.port?`http://127.0.0.1:${s.port}`:null;if(!i)return{output:""};const l=process.env.OPENCODE_SERVER_PASSWORD,c=l?{Authorization:`Basic ${Buffer.from(`${process.env.OPENCODE_SERVER_USERNAME||"opencode"}:${l}`).toString("base64")}`}:{},u=await fetch(`${i}/session/${t}/message?limit=5`,{headers:c});if(!u.ok)return{output:""};const p=(await u.json()).filter(t=>"assistant"===t.info.role);return{output:p.flatMap(t=>t.parts).filter(t=>"text"===t.type&&t.text).map(t=>t.text).join("\n"),lastMessageId:p[0]?.info?.id}}catch{return{output:""}}}(a,p);return void l(y,{eventType:"session_idle",sessionId:a,variables:{sessionId:a,lastOutput:r,lastMessageId:s||""}})}case"session.created":{const e=t.properties.info?.id||"";if(!e)return;return void setTimeout(()=>{l(y,{eventType:"session_created",sessionId:e,variables:{sessionId:e}})},500)}}}};return i=g,g};export const internals={ceilingNotice:r,MCP_RESULT_CEILING_CHARS:a,parallelNoteCall:w,appendToResult:b};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{appendFileSync as e,mkdirSync as s}from"fs";import{join as t}from"path";const n="true"===process.env.ALCHEMY_DEBUG_LOGS,r=(r,o,l)=>{if(!n)return;const i=`[${(new Date).toISOString()}] ${o}${l?" "+JSON.stringify(l):""}\n`;try{s(t(r,".."),{recursive:!0}),e(r,i)}catch(e){}};export default async({directory:o})=>{const l=(e=>t(e,".alchemy_lab","system-prompt.log"))(o);return r(l,"system-logger plugin loaded",{directory:o}),{"experimental.chat.system.transform":async(o,i)=>{const a=i.system.some(
|
|
1
|
+
import{appendFileSync as e,mkdirSync as s}from"fs";import{join as t}from"path";const n="true"===process.env.ALCHEMY_DEBUG_LOGS,r=(r,o,l)=>{if(!n)return;const i=`[${(new Date).toISOString()}] ${o}${l?" "+JSON.stringify(l):""}\n`;try{s(t(r,".."),{recursive:!0}),e(r,i)}catch(e){}};export default async({directory:o})=>{const l=(e=>t(e,".alchemy_lab","system-prompt.log"))(o);return r(l,"system-logger plugin loaded",{directory:o}),{"experimental.chat.system.transform":async(o,i)=>{const a=i.system.some(e=>e.includes("head of engineering"));if(n&&r(l,"Alchemist detection",{isAlchemist:a,sessionID:o.sessionID,systemParts:i.system.length,partLengths:i.system.map(e=>e.length),hasSpecialist:i.system.map(e=>e.includes("specialist_ops"))}),a&&(function(e){for(let s=0;s<e.length;s++){let t=e[s];t=t.replace(/^- When doing file search, prefer to use the Task tool.*$/gm,""),t=t.replace(/^- You should proactively use the Task tool.*$/gm,""),t=t.replace(/^- VERY IMPORTANT:.*use the Task tool instead of running search commands directly\.$/gm,""),t=t.replace(/^- If the user specifies that they want you to run tools "in parallel".*multiple Task tool calls\.$/gm,""),t=t.replace(/<example>\n.*?\[Uses the Task tool.*?<\/example>/gs,""),t=t.replace(/\n{3,}/g,"\n\n"),e[s]=t}}(i.system),r(l,"Stripped Task tool references for alchemist session",{sessionID:o.sessionID})),!n)return;const c=i.system.some(e=>e.includes("referenced the following")||e.includes("entity")),m=["=".repeat(80),`Timestamp: ${(new Date).toISOString()}`,`Session: ${o.sessionID||"N/A"}`,`Model: ${o.model?.providerID||"?"}/${o.model?.modelID||"?"}`,`System parts: ${i.system.length}`,`Has entity context: ${c}`,"-".repeat(80),...i.system.map((e,s)=>{const t=e.length>500?e.slice(0,250)+"\n...[truncated]...\n"+e.slice(-250):e;return`--- Part ${s} (${e.length} chars) ---\n${t}`}),"=".repeat(80),""];try{s(t(l,".."),{recursive:!0}),e(l,m.join("\n")+"\n");const n=t(l,"..","system-prompt-full.log"),r=[`Timestamp: ${(new Date).toISOString()}`,`Session: ${o.sessionID||"N/A"}`,`IsAlchemist: ${a}`,`System parts: ${i.system.length}`,...i.system.map((e,s)=>`--- Part ${s} (${e.length} chars) ---\n${e}`),"=".repeat(80)],{writeFileSync:c}=require("fs");c(n,r.join("\n")+"\n")}catch(e){}}}};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alchemylab",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "AlchemyLab: the agentic workbench. Work is a request, with criteria, gates and a receipt.",
|
|
6
6
|
"author": "Testfire Software",
|
|
@@ -45,16 +45,19 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@modelcontextprotocol/sdk": "^1.7.0",
|
|
48
|
-
"alchemylab-opencode": "^1.0.
|
|
48
|
+
"alchemylab-opencode": "^1.0.23",
|
|
49
49
|
"chalk": "^4.1.2",
|
|
50
50
|
"compression": "^1.8.1",
|
|
51
51
|
"cors": "^2.8.5",
|
|
52
52
|
"express": "^4.18.2",
|
|
53
|
+
"js-yaml": "^3.14.2",
|
|
53
54
|
"jszip": "^3.10.2",
|
|
54
55
|
"micromatch": "^4.0.5",
|
|
55
56
|
"pdf-lib": "^1.17.1",
|
|
56
57
|
"playwright-core": "^1.61.1",
|
|
57
58
|
"simple-git": "^3.36.0",
|
|
59
|
+
"ulid": "^3.0.1",
|
|
60
|
+
"undici": "^7.25.0",
|
|
58
61
|
"unpdf": "^1.8.1",
|
|
59
62
|
"winston": "^3.8.2",
|
|
60
63
|
"ws": "^8.14.2",
|
package/dist/19.js
DELETED
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
exports.id=19,exports.ids=[19],exports.modules={16554:(e,exports,t)=>{function n(e,t,n){if(T)try{const s=`[${(new Date).toISOString()}] ${t}${n?" "+JSON.stringify(n):""}\n`,o=(0,x.join)(e.basePath||process.cwd(),".alchemy_lab","spawn-debug.log");(0,k.appendFileSync)(o,s)}catch{}}async function s(e,n,s,o,i,r){if(!(e&&n&&s&&o))return null
|
|
3
|
-
try{const i=await e.proxyPost(`/api/projects/${n}/requests/${s}/pickup-compose`,{sessionId:o}),a=i?.data?.text??i?.text,l="string"==typeof a&&a.trim()?a.trim():null
|
|
4
|
-
if(l&&/Project map/.test(l))return l
|
|
5
|
-
let c=null
|
|
6
|
-
try{const{generateProjectMap:e}=await t.e(491).then(t.t.bind(t,23491,23))
|
|
7
|
-
c=e(r||process.cwd())}catch{c=null}return l||c?[l,c].filter(Boolean).join("\n\n"):null}catch(e){return i.warn("pickup-compose failed; the association hook will deliver guidance as an inject",{requestId:s,error:(0,v.getErrorMessage)(e)}),null}}async function o(e){const{apiClient:t,fromSessionId:n,toSessionId:s,body:o,requestId:i,logger:r}=e
|
|
8
|
-
if(!t||!n)return
|
|
9
|
-
const a=t.getSessionMessageClient()
|
|
10
|
-
if(a)try{const e=await a.createInstruction({fromSessionId:n,toSessionId:s,body:o,...i?{requestId:i}:{}})
|
|
11
|
-
return e?.messageCode}catch(e){return void r.warn("Failed to mint instruction code",{error:(0,v.getErrorMessage)(e),fromSessionId:n,toSessionId:s})}}async function i(e,t,n,s,o){if(e&&t&&n)try{await e.proxyPost(`/api/projects/${t}/session-messages/${encodeURIComponent(n)}/delivered`,{ok:s.ok,error:s.detail||s.error,messageId:s.messageId})}catch(e){o.warn("instruction delivery receipt not written",{instructionCode:n,error:(0,v.getErrorMessage)(e)})}}async function r(e,t,r,a,l){const{agent:c="work",prompt:d,requestId:u,allowParallel:g=!1,useExistingSession:p}=e
|
|
12
|
-
if(n(t,"handleSpawn called",{agent:c,promptLength:d.length,requestId:u,useExistingSession:p,cliOriginSessionId:l?.sessionId||null}),!(0,A.isValidAgent)(c))return{content:[{type:"text",text:`\u274c Unknown agent '${c}'.\n\n**Available agents:** ${(0,A.getAgentNames)().join(", ")}\n\nChoose one of the available agents listed above to see detailed descriptions of each agent.`}],isError:!0}
|
|
13
|
-
const f=l?.sessionId,h=f?I.sessionIdentity.getAgentTypeFor(f).then((e=>e||void 0)):Promise.resolve(void 0),m=async function(e){try{const t=`http://localhost:${j}/api/agents/by-name/${encodeURIComponent(e)}`,n=await fetch(t,{signal:AbortSignal.timeout(8e3)})
|
|
14
|
-
if(!n.ok)return null
|
|
15
|
-
const s=await n.json()
|
|
16
|
-
return s.success?s.data??null:null}catch{return null}}(c).catch((()=>null)),k=(0,y.getServerUrl)(t,r),x=(async()=>{if(!a||!u)return null
|
|
17
|
-
const e=a.getSessionRequestAssociationClient()
|
|
18
|
-
return e?await e.getSessionsForRequest(u,!0):null})().catch((e=>(r.debug("Failed to check for existing workers",{error:(0,v.getErrorMessage)(e)}),null))),[E,q,P,U]=await Promise.all([h,m,k,x])
|
|
19
|
-
try{if(n(t,"Spawn agent type check",{callerSessionId:f||null,callerAgentType:E||null,pid:process.pid}),E){const e=(0,A.getAllowedSubagents)(E)
|
|
20
|
-
if(e&&!e.includes(c))return{content:[{type:"text",text:`\u274c Agent type '${E}' cannot spawn '${c}'.\n\n**Allowed subagents for ${E}:** ${e.join(", ")}\n\nUse one of the allowed agent types instead.`}],isError:!0}}}catch(e){n(t,"allowedSubagents check failed",{error:(0,v.getErrorMessage)(e)})}let R=q?.requestContextMode
|
|
21
|
-
if(!R){const e=(0,A.getBuiltInAgentConfig)(c)
|
|
22
|
-
R=e?.requestContextMode}if(R&&"none"!==R&&!u)return{content:[{type:"text",text:`\u274c Agent '${c}' requires a requestId to be provided.\n\nThis agent has requestContextMode: '${R}' which means it needs to work in the context of a specific request.\n\nPlease provide a requestId when spawning this agent.`}],isError:!0}
|
|
23
|
-
if(u&&"required"===R&&a)try{const e=await a.getRequestClient().getRequest(u)
|
|
24
|
-
if("draft"===e?.status){const t=e?.intake,n="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"
|
|
25
|
-
return{content:[{type:"text",text:`\u274c ${u} is a DRAFT: ${n}.\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){n(t,"draft-spawn guard read failed (continuing)",{error:(0,v.getErrorMessage)(e)})}if(n(t,"serverUrl resolved",{serverUrl:P}),!t.workspaceManager?.getCurrentContext(t.currentSessionId)?.basePath&&!t.basePath)throw new w.ValidationError("Working directory not available in context")
|
|
26
|
-
const M=l?.sessionId
|
|
27
|
-
let O=""
|
|
28
|
-
if(U){const e=(M?U.filter((e=>e.opencodeSessionId!==M)):U).filter((e=>!1!==e.working))
|
|
29
|
-
if(e.length>0){const t=e.map((e=>e.opencodeSessionId)).join(", ")
|
|
30
|
-
if(!g)return r.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}
|
|
31
|
-
O=`\u26a0\ufe0f Warning: Request ${u} already has ${e.length} active worker(s): ${t}. Proceeding anyway (allowParallel=true).\n\n`,r.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,L,_=d
|
|
32
|
-
u&&(D=`requests/${u}`,n(t,"Setting initialBranch for agent",{agent:c,requestId:u,initialBranch:D,agentRequestContextMode:R||"undefined"}),_="readonly"===R?`Working on request ${u} (READONLY mode - you cannot modify files, only explore and report).\n\n${d}`:`Working on request ${u}.\n\n${d}`)
|
|
33
|
-
let F,N=!1
|
|
34
|
-
if(p){if(L=p,r.info("Using existing session for spawn",{sessionId:L,requestId:u}),!P)throw new w.ValidationError("Could not determine OpenCode server URL")
|
|
35
|
-
try{let e
|
|
36
|
-
try{const t=await fetch(`http://localhost:${j}/api/project-settings`,{signal:AbortSignal.timeout(8e3)})
|
|
37
|
-
if(t.ok){const n=await t.json()
|
|
38
|
-
if(n.data?.defaultModel){const[t,...s]=n.data.defaultModel.split("/")
|
|
39
|
-
e={providerID:t,modelID:s.join("/")}}}}catch{}F=await o({apiClient:a,fromSessionId:l?.sessionId,toSessionId:L,body:_,requestId:u,logger:r})
|
|
40
|
-
let n=_
|
|
41
|
-
const d=await s(a,t.projectId,u,L,r,t.mainBasePath||t.basePath)
|
|
42
|
-
d&&(n=`${d}\n\n---\n\n${n}`)
|
|
43
|
-
const g={body:_,fromSessionId:l?.sessionId,fromAgent:E,...u?{requestId:u}:{},...F?{instructionCode:F}:{}},p=await(0,S.deliverToSession)(L,n,{kind:"agent-delegation",partPayload:g})
|
|
44
|
-
if(await i(a,t.projectId,F,p,r),!p.ok)throw new Error((0,S.deliveryFailureText)(L,p))
|
|
45
|
-
r.info("Prompt delivered to existing session",{sessionId:L,agent:c,messageId:p.messageId})}catch(e){throw new Error(`Failed to use existing session: ${(0,v.getErrorMessage)(e)}`)}}else{N=!0,n(t,"Creating session via spawn-session endpoint")
|
|
46
|
-
const i=M
|
|
47
|
-
T&&(0,b.logSessionIdentity)("subagent_operations.spawn","_meta",{parentSessionId:i})
|
|
48
|
-
try{const p=`http://localhost:${j}/api/spawn-session`,f=await fetch(p,{method:"POST",signal:AbortSignal.timeout(15e3),headers:{"Content-Type":"application/json"},body:JSON.stringify({agent:c,prompt:d,requestId:u,parentSessionId:i,title:e.title,allowParallel:g,callerAgentType:E})})
|
|
49
|
-
if(!f.ok){const e=await f.text().catch((()=>"Unknown error"))
|
|
50
|
-
throw new Error(`Spawn session endpoint failed: ${f.status} ${e}`)}const h=await f.json()
|
|
51
|
-
if(!h.success||!h.data)throw new Error(h.error||"Spawn session returned unsuccessful")
|
|
52
|
-
const{sessionId:m,model:w,serverUrl:y,initialBranch:S}=h.data
|
|
53
|
-
D=S,F=await o({apiClient:a,fromSessionId:l?.sessionId,toSessionId:m,body:_,requestId:u,logger:r})
|
|
54
|
-
let I=_
|
|
55
|
-
const b="pickupGuidance"in(h?.data??{})?h.data.pickupGuidance??null:await s(a,t.projectId,u,m,r,t.mainBasePath||t.basePath)
|
|
56
|
-
b&&(I=`${b}\n\n---\n\n${I}`)
|
|
57
|
-
const v=await(0,$.deliverInitialPrompt)({serverUrl:y,sessionId:m,agent:c,prompt:I,model:w,directory:t.mainBasePath,metadata:{alchemy:{kind:"agent-delegation",payload:{body:_,fromSessionId:l?.sessionId,fromAgent:E,...u?{requestId:u}:{},...F?{instructionCode:F}:{}}}}})
|
|
58
|
-
if(!v.success)throw new Error(`Failed to spawn subagent: ${v.error}`)
|
|
59
|
-
L=m,n(t,"Spawn successful via unified endpoint",{sessionId:m,parentSessionId:i,model:w,instructionCode:F}),r.info("Background subagent spawned via unified endpoint",{agent:c,requestId:u,sessionId:m,parentSessionId:i,instructionCode:F})}catch(e){throw new Error(`Failed to spawn subagent: ${(0,v.getErrorMessage)(e)}`)}}let B=O
|
|
60
|
-
B+=p?`Prompt sent to existing session ${L}.`:`Background ${c} subagent spawned successfully.`,u&&(B+=`\nWorking on: ${u}`),F&&(B+=`\nInstruction code: ${F} (the agent will cite this on its reports/questions via relatesTo)`),B+="\n\nThe subagent is now working independently. You can continue with other tasks."
|
|
61
|
-
const V=!!L&&"unknown"!==L&&"spawning"!==L
|
|
62
|
-
return{content:[{type:"text",text:B}],...(0,C.alchemyMeta)({kind:"spawn-subagent",spawnedSessionId:V?L:void 0,agentType:c,requestId:u||void 0,description:e.title||d.slice(0,50)||c,...F?{instructionCode:F}:{}}),...F?{instructionCode:F}:{}}}async function a(e,t,n,s,r,a,l){if(!await(0,y.getServerUrl)(n,s))throw new w.ValidationError("Could not determine OpenCode server URL")
|
|
63
|
-
if(s.info("Sending message to subagent session",{sessionId:e,promptLength:t.length}),r)try{const t=l?.sessionId
|
|
64
|
-
if(t){const n=r.getCLISessionClient()
|
|
65
|
-
if(n){let o=await n.getByExternalId(t)
|
|
66
|
-
if(o||(o=await n.createOrUpdateSession({externalSessionId:t,providerId:"opencode",status:"active"}),s.info("Created caller session in DB for re-parenting",{callerSessionId:t,dbId:o?.id})),o){const i=await n.getByExternalId(e).catch((()=>null)),r=i?.parentSessionId??null
|
|
67
|
-
r===o.id?s.debug("Parent unchanged for continued agent; no re-parent write",{sessionId:e}):(await n.createOrUpdateSession({externalSessionId:e,providerId:"opencode",parentSessionId:o.id,status:"active"}),s.info("RE-PARENTED continued agent: reports now flow to the current caller",{sessionId:e,fromParentDbId:r,toParentDbId:o.id,toCallerSessionId:t}))}}}}catch(e){s.warn("Failed to update parent session - reports may go to wrong parent",{error:(0,v.getErrorMessage)(e)})}let c=a
|
|
68
|
-
if(!c)try{const t=`http://localhost:${j}/api/sessions/${encodeURIComponent(e)}/agent-type`,n=await fetch(t,{signal:AbortSignal.timeout(8e3)})
|
|
69
|
-
if(n.ok){const e=await n.json()
|
|
70
|
-
e.success&&e.agentType&&(c=e.agentType)}}catch{s.warn("Agent type lookup failed for session",{sessionId:e})}if(!c)throw new w.ValidationError(`Cannot continue session ${e}: unable to determine agent type. The session's agent type could not be looked up from the action server.`)
|
|
71
|
-
try{let a
|
|
72
|
-
try{const e=await fetch(`http://localhost:${j}/api/project-settings`,{signal:AbortSignal.timeout(8e3)})
|
|
73
|
-
if(e.ok){const t=await e.json()
|
|
74
|
-
if(t.data?.defaultModel){const[e,...n]=t.data.defaultModel.split("/")
|
|
75
|
-
a={providerID:e,modelID:n.join("/")}}}}catch{}const d=await o({apiClient:r,fromSessionId:l?.sessionId,toSessionId:e,body:t,logger:s}),u=t,g={body:t,fromSessionId:l?.sessionId,fromAgent:await I.sessionIdentity.getAgentTypeFor(l?.sessionId)||void 0,...d?{instructionCode:d}:{}},p=await(0,S.deliverToSession)(e,u,{kind:"agent-followup",partPayload:g})
|
|
76
|
-
return await i(r,n.projectId,d,p,s),p.ok?(s.info("Message delivered to subagent session",{sessionId:e,agent:c,instructionCode:d,messageId:p.messageId}),{content:[{type:"text",text:[d?`Message delivered to session ${e} (${d}); it is in that session's transcript.`:`Message delivered to session ${e}; it is in that session's transcript.`,c?`That session is a ${c}. It will process this in the background -- it is NOT proof that work started; check for tasks before reporting progress.`:"Role unknown for that session. It will process this in the background -- that is not proof work started; check for tasks before reporting progress."].join("\n")}],...d?{_meta:{alchemy:{kind:"continue-subagent",instructionCode:d}},instructionCode:d}:{}}):{content:[{type:"text",text:(0,S.deliveryFailureText)(e,p)+(c?` That session is a ${c}.`:"")}],isError:!0,...d?{_meta:{alchemy:{kind:"continue-subagent",instructionCode:d,failed:!0}},instructionCode:d}:{}}}catch(e){throw new Error(`Failed to continue session: ${(0,v.getErrorMessage)(e)}`)}}function l(e){const t=Math.floor(e/1e3)
|
|
77
|
-
if(t<60)return`${t}s`
|
|
78
|
-
const n=Math.floor(t/60)
|
|
79
|
-
return n<60?`${n}m ${t%60}s`:`${Math.floor(n/60)}h ${n%60}m`}function c(e){const t=[]
|
|
80
|
-
for(const n of e)if("assistant"===n.info.role&&n.parts)for(const e of n.parts)if("tool"===e.type&&e.tool&&e.state){const s=e.state.input||{}
|
|
81
|
-
let o=e.tool.replace(/^alchemy_/,"")
|
|
82
|
-
const i=s.path||s.file||s.directory,r=s.needle||s.query||s.pattern
|
|
83
|
-
"string"==typeof i?o+=` ${i.split("/").pop()||i}`:"string"==typeof r&&(o+=` "${r.length>30?r.slice(0,27)+"...":r}"`),t.push({name:o,state:e.state.status,time:n.info.time.created})}t.sort(((e,t)=>t.time-e.time))
|
|
84
|
-
const n=t.find((e=>"pending"===e.state||"running"===e.state)),s=t.filter((e=>"completed"===e.state||"error"===e.state)).slice(0,3),o=t.length>0?t[0].time:null
|
|
85
|
-
return{current:n?.name??null,recent:s.map((e=>e.name)),lastActivityTime:o}}function d(e){return e<1e3?"<1s ago":e<6e4?`${Math.floor(e/1e3)}s ago`:e<36e5?`${Math.floor(e/6e4)}m ago`:`${Math.floor(e/36e5)}h ago`}function u(e,t){const n=e||t,s=Date.now()-n
|
|
86
|
-
if(e&&s<q)return{status:"working",detail:`last action ${d(s)}`,isReady:!1}
|
|
87
|
-
const o=d(s).replace(/ ago$/,"")
|
|
88
|
-
return s>P&&e?{status:"stalled",detail:`no activity for ${o}`,isReady:!0}:e?{status:"idle",detail:`no activity for ${o}`,isReady:!0}:{status:"idle",detail:"no tool activity",isReady:!0}}function g(e){let t=0,n=0,s=0
|
|
89
|
-
for(const o of e.trim().split("\n")){if(!o)continue
|
|
90
|
-
const[e,i]=o.split("\t")
|
|
91
|
-
"-"!==e&&(t+=parseInt(e,10)||0),"-"!==i&&(n+=parseInt(i,10)||0),s++}return{additions:t,deletions:n,files:s}}function p(e,t,n,s){const o=e.get(t)
|
|
92
|
-
return e.set(t,{at:s,fingerprint:n}),o&&o.fingerprint===n?`Nothing changed since your last check at ${new Date(o.at).toISOString().slice(11,19)} UTC (${d(s-o.at)}): same activity, same messages, same tokens.`:null}async function f(e,n,s,o){const i=await(0,y.getServerUrl)(n,s)
|
|
93
|
-
if(!i)throw new w.ValidationError("Could not determine OpenCode server URL")
|
|
94
|
-
s.info("Checking status of subagent session",{sessionId:e})
|
|
95
|
-
try{const r=`${i.replace(/\/$/,"")}/session/${e}`,a=await fetch(r,{signal:AbortSignal.timeout(8e3)})
|
|
96
|
-
if(!a.ok)return{content:[{type:"text",text:`Session ${e} not found or has exited.`}],isError:!0}
|
|
97
|
-
const d=await a.json(),f=`${i.replace(/\/$/,"")}/session/${e}/message`,h=await fetch(f,{signal:AbortSignal.timeout(8e3)})
|
|
98
|
-
let m={input:0,output:0,reasoning:0},w="",$=u(null,d.time.updated),y=-1
|
|
99
|
-
if(h.ok){const e=await h.json()
|
|
100
|
-
y=e.length
|
|
101
|
-
for(const t of e)"assistant"===t.info.role&&t.info.tokens&&(m.input+=t.info.tokens.input||0,m.output+=t.info.tokens.output||0,m.reasoning+=t.info.tokens.reasoning||0)
|
|
102
|
-
const t=c(e)
|
|
103
|
-
$=u(t.lastActivityTime,d.time.updated),t.current&&(w+=`\nCurrent: ${t.current}`),t.recent.length>0&&(w+=`\nRecent: ${t.recent.join(", ")}`)}const S=Date.now()-d.time.created,I=$.status,b=$.isReady,v=m.input+m.output+m.reasoning
|
|
104
|
-
let k="",x="",A=null
|
|
105
|
-
if(o)try{const t=o.getSessionRequestAssociationClient()
|
|
106
|
-
if(t){const n=await t.getActiveRequestsForSession(e,!1)
|
|
107
|
-
if(n.length>0){const t=n.filter((e=>!e.endedAt)).sort(((e,t)=>new Date(t.startedAt).getTime()-new Date(e.startedAt).getTime())),o=n.filter((e=>e.endedAt)).sort(((e,t)=>new Date(t.endedAt).getTime()-new Date(e.endedAt).getTime())),i=o[0],r=t[0]
|
|
108
|
-
i&&r?A=new Date(i.endedAt).getTime()>new Date(r.startedAt).getTime()?i.requestLocalId:r.requestLocalId:i?A=i.requestLocalId:r&&(A=r.requestLocalId)
|
|
109
|
-
const a=[]
|
|
110
|
-
t.length>0&&a.push(`Active: ${t.map((e=>e.requestLocalId)).join(", ")}`),o.length>0&&a.push(`Previous: ${o.map((e=>e.requestLocalId)).join(", ")}`),a.length>0&&(x=`\nRequests: ${a.join(" | ")}`),s.debug("Found request associations",{sessionId:e,activeCount:t.length,historicalCount:o.length})}}}catch(e){s.debug("Failed to get request associations, falling back to title extraction",{error:e instanceof Error?e.message:String(e)})}if(A||(A=function(e){const t=e.match(/\[(req\d{6})\]/)
|
|
111
|
-
return t?t[1]:null}(d.title||"")),A&&n.basePath){const e=await async function(e,n){try{const{execFileSync:s}=await Promise.resolve().then(t.t.bind(t,35317,23)),o=`requests/${e}`
|
|
112
|
-
let i=!1
|
|
113
|
-
try{s("git",["rev-parse","--verify",o],{cwd:n,stdio:"pipe"}),i=!0}catch{i=!1}if(i){const e=s("git",["diff",`main...${o}`,"--numstat"],{cwd:n,encoding:"utf8"})
|
|
114
|
-
if(e.trim())return g(e)}try{const t=s("git",["log","main","--merges","--oneline","-n","50",`--grep=${e}`],{cwd:n,encoding:"utf8"}).trim()
|
|
115
|
-
if(t){const e=t.split("\n")[0].split(" ")[0],o=s("git",["diff",`${e}^1...${e}`,"--numstat"],{cwd:n,encoding:"utf8"})
|
|
116
|
-
if(o.trim())return{...g(o),merged:!0}}}catch{}return null}catch{return null}}(A,n.basePath)
|
|
117
|
-
if(e){const t=e.additions+e.deletions,n=e.merged?" (merged)":""
|
|
118
|
-
k=`\nDiff vs main (${A}): +${e.additions}/-${e.deletions} lines (${t} total) in ${e.files} file${1!==e.files?"s":""}${n}`}}const C=p(U,`${n.currentSessionId??""}>${e}`,`${d.time.updated}:${y}:${v}`,Date.now())
|
|
119
|
-
return{content:[{type:"text",text:`${C?`${C}\n\n`:""}Session ${e}\nTitle: ${d.title||"Untitled"}\nStatus: ${I} (${$.detail})\nReady for input: ${b?"Yes":"No"}\nAge: ${l(S)}\nTokens: ${v.toLocaleString()} (in: ${m.input.toLocaleString()}, out: ${m.output.toLocaleString()}${m.reasoning>0?`, reasoning: ${m.reasoning.toLocaleString()}`:""})${w}${x}${k}`}]}}catch(e){throw new Error(`Failed to check session status: ${(0,v.getErrorMessage)(e)}`)}}async function h(e,t,n){const s=await(0,y.getServerUrl)(t,n)
|
|
120
|
-
if(!s)throw new w.ValidationError("Could not determine OpenCode server URL")
|
|
121
|
-
n.info("Aborting subagent session",{sessionId:e})
|
|
122
|
-
try{const t=`${s.replace(/\/$/,"")}/session/${e}/abort`,o=await fetch(t,{signal:AbortSignal.timeout(8e3),method:"POST"})
|
|
123
|
-
if(!o.ok){const e=await o.text().catch((()=>"Unknown error"))
|
|
124
|
-
throw new Error(`Failed to abort session: ${o.status} ${e}`)}return n.info("Session aborted",{sessionId:e}),{content:[{type:"text",text:`Session ${e} has been aborted.`}]}}catch(e){throw new Error(`Failed to abort session: ${(0,v.getErrorMessage)(e)}`)}}async function m(e,t,n,s={}){const{activeOnly:o=!1,requestId:i,limit:r,minTokens:a,maxTokens:d,maxAgeHours:g}=s,p=await(0,y.getServerUrl)(e,t)
|
|
125
|
-
if(!p)throw new w.ValidationError("Could not determine OpenCode server URL")
|
|
126
|
-
t.info("Listing sessions",{filters:s})
|
|
127
|
-
try{const e=`${p.replace(/\/$/,"")}/session?limit=1000`,t=await fetch(e,{signal:AbortSignal.timeout(8e3)})
|
|
128
|
-
if(!t.ok)throw new Error(`Failed to fetch sessions: ${t.status}`)
|
|
129
|
-
let f=await t.json()
|
|
130
|
-
if(0===f.length)return{content:[{type:"text",text:"No sessions found."}]}
|
|
131
|
-
s.parentSessionId&&(f=f.filter((e=>(e.parentId||e.parentID)===s.parentSessionId))),f.sort(((e,t)=>t.time.created-e.time.created))
|
|
132
|
-
const h=`${p.replace(/\/$/,"")}/session/status`,m=await fetch(h,{signal:AbortSignal.timeout(8e3)}),w=m.ok?await m.json():{}
|
|
133
|
-
let $=f
|
|
134
|
-
if(o&&($=$.filter((e=>"idle"!==(w[e.id]?.type||"idle")))),void 0!==g){const e=60*g*60*1e3,t=Date.now()-e
|
|
135
|
-
$=$.filter((e=>e.time.created>=t))}if(0===$.length)return{content:[{type:"text",text:"No sessions match the specified filters."}]}
|
|
136
|
-
let y={}
|
|
137
|
-
const S=$.map((e=>e.id))
|
|
138
|
-
if(n)try{const e=n.getCLISessionClient()
|
|
139
|
-
e&&(y=await e.batchEnrich(S))}catch{}const I=p.replace(/\/$/,""),b=await Promise.allSettled($.map((e=>fetch(`${I}/session/${e.id}/message`,{signal:AbortSignal.timeout(8e3)}).then((e=>e.ok?e.json():[])).catch((()=>[]))))),v=[]
|
|
140
|
-
for(let e=0;e<$.length;e++){const t=$[e],n=Date.now()-t.time.created
|
|
141
|
-
let o=0,r=null,l=[],g=u(null,t.time.updated)
|
|
142
|
-
const p=b[e],f="fulfilled"===p.status?p.value:[]
|
|
143
|
-
for(const e of f)"assistant"===e.info.role&&e.info.tokens&&(o+=(e.info.tokens.input||0)+(e.info.tokens.output||0)+(e.info.tokens.reasoning||0))
|
|
144
|
-
if(f.length>0){const e=c(f)
|
|
145
|
-
g=u(e.lastActivityTime,t.time.updated),r=e.current||null,l=e.recent}const h=g.status
|
|
146
|
-
if(void 0!==a&&o<a)continue
|
|
147
|
-
if(void 0!==d&&o>d)continue
|
|
148
|
-
const m=y[t.id]
|
|
149
|
-
if(s.agentType&&(!m||m.agentType!==s.agentType))continue
|
|
150
|
-
if("archived"===m?.status)continue
|
|
151
|
-
let w=""
|
|
152
|
-
const S=[],I=[]
|
|
153
|
-
if(m?.associations&&I.push(...m.associations),I.length>0){const e=new Map
|
|
154
|
-
for(const t of I){const n=e.get(t.requestLocalId)
|
|
155
|
-
void 0!==n&&(n||t.endedAt)||e.set(t.requestLocalId,!t.endedAt)}const t=[...e.entries()].filter((([,e])=>e)).map((([e])=>e)),n=[...e.entries()].filter((([,e])=>!e)).map((([e])=>e))
|
|
156
|
-
S.push(...t,...n)
|
|
157
|
-
const s=[]
|
|
158
|
-
if(t.length>0&&s.push(`active: ${t.join(", ")}`),n.length>0){const e=5,t=n.slice(0,e),o=n.length-t.length
|
|
159
|
-
s.push(`prev: ${t.join(", ")}${o>0?` +${o} more`:""}`)}s.length>0&&(w=` [${s.join(" | ")}]`)}if(i&&!S.includes(i))continue
|
|
160
|
-
const k=t.title||"Untitled",x=k.length>50?k.slice(0,47)+"...":k
|
|
161
|
-
v.push({id:t.id,title:x,status:h,age:n,totalTokens:o,requestsInfo:w,allRequestIds:S,statusDetail:g.detail,currentAction:r,recentActions:l})}if(0===v.length)return{content:[{type:"text",text:"No sessions match the specified filters."}]}
|
|
162
|
-
const k=r?v.slice(0,r):v,x=k.map((e=>{const t=e.currentAction?`\n Current: ${e.currentAction}`:"",n=e.recentActions.length>0?`\n Recent: ${e.recentActions.join(", ")}`:""
|
|
163
|
-
return`\u2022 ${e.id}\n ${e.title}\n Status: ${e.status} (${e.statusDetail}) | Age: ${l(e.age)} | ${e.totalTokens.toLocaleString()} tokens${e.requestsInfo}${t}${n}`})),A=r&&v.length>r?` (showing ${r} of ${v.length})`:""
|
|
164
|
-
return{content:[{type:"text",text:`Found ${k.length} session${1!==k.length?"s":""}${A}:\n\n${x.join("\n\n")}`}]}}catch(e){throw new Error(`Failed to list sessions: ${(0,v.getErrorMessage)(e)}`)}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.handleSpawn=r,exports.handleContinue=a,exports.extractRecentActivity=c,exports.formatTimeSince=d,exports.deriveActivityStatus=u,exports.noteStatusCheck=p,exports.handleCheckStatus=f,exports.handleAbort=h,exports.handleListSessions=m,exports.handleSubagentOperations=async function(e,t,n,s,o,i){const l=n.child({tool:"subagent_operations"}),c=s.startTimer("tool_execution_time")
|
|
165
|
-
try{const n=e,{sessionId:d,operation:u}=n
|
|
166
|
-
let g
|
|
167
|
-
switch(l.info("Processing subagent_operations",{operation:u,sessionId:d}),u){case"spawn":g=await r({agent:n.agent,prompt:n.prompt,requestId:n.requestId,allowParallel:n.allowParallel,useExistingSession:n.useExistingSession},t,l,o,i)
|
|
168
|
-
break
|
|
169
|
-
case"continue":g=await a(d,n.prompt,t,l,o,void 0,i)
|
|
170
|
-
break
|
|
171
|
-
case"check-status":g=await f(d,t,l,o)
|
|
172
|
-
break
|
|
173
|
-
case"abort":g=await h(d,t,l)
|
|
174
|
-
break
|
|
175
|
-
case"read-messages":{const e=!(!n.compact&&null==n.select),s=!e&&null==n.limit,o=n.limit??(e?50:8)
|
|
176
|
-
g=await async function(e,t,n,s,o){const i=await(0,y.getServerUrl)(n,s)
|
|
177
|
-
if(!i)throw new w.ValidationError("Could not determine OpenCode server URL")
|
|
178
|
-
s.info("Reading messages from subagent session",{sessionId:e,limit:t,compact:o?.compact,select:o?.select})
|
|
179
|
-
try{const n=`${i.replace(/\/$/,"")}/session/${e}/message?limit=${t}`,s=await fetch(n,{signal:AbortSignal.timeout(8e3)})
|
|
180
|
-
if(!s.ok){if(404===s.status)return{content:[{type:"text",text:`Session ${e} not found.`}],isError:!0}
|
|
181
|
-
throw new Error(`Failed to fetch messages: ${s.status}`)}const r=await s.json()
|
|
182
|
-
if(0===r.length)return{content:[{type:"text",text:`Session ${e} has no messages yet.`}]}
|
|
183
|
-
const a=(e,t)=>e.length>t?e.slice(0,t)+"\u2026[truncated]":e,l=e=>"user"===e.info.role?"USER":"ASSISTANT",c=e=>new Date(e.info.time.created).toLocaleTimeString(),d=e=>`\u{1f527} ${e.tool||"tool"}${"error"===e.state?.status?" \u2717":""}`,u=e=>Array.isArray(e)?e.map((e=>"image"===e?.type?"[image]":"string"==typeof e?.text?e.text:JSON.stringify(e))).join(" "):"string"==typeof e?e:JSON.stringify(e??"")
|
|
184
|
-
if("number"==typeof o?.select){const t=r[o.select-1]
|
|
185
|
-
if(!t)return{content:[{type:"text",text:`No message #${o.select} (session has ${r.length}; use compact to index).`}],isError:!0}
|
|
186
|
-
const n=[`Session ${e}: message ${o.select} of ${r.length}: ${l(t)} (${c(t)}):`,""]
|
|
187
|
-
for(const e of t.parts)if("text"===e.type&&e.text)n.push(`TEXT: ${a(e.text,6e3)}`)
|
|
188
|
-
else if("tool"===e.type){const t=e.state||{}
|
|
189
|
-
n.push(`\u{1f527} ${e.tool||"tool"} [${t.status??"unknown"}]`),n.push(` input: ${a("string"==typeof t.input?t.input:JSON.stringify(t.input??{}),2500)}`)
|
|
190
|
-
const s=u(t.output)
|
|
191
|
-
s&&n.push(` output: ${a(s,1500)}`)}return{content:[{type:"text",text:n.join("\n")}]}}if(o?.compact){const t=r.map(((e,t)=>{const n=e.parts.filter((e=>"tool"===e.type)).map(d),s=e.parts.filter((e=>"text"===e.type&&e.text)).map((e=>e.text)).join(" ").replace(/\s+/g," ").trim().slice(0,140),o=[...n,s?`"${s}${s.length>=140?"\u2026":""}"`:""].filter(Boolean).join(" \xb7 ")
|
|
192
|
-
return`[${t+1}] ${"USER"===l(e)?"USER":"ASST"} (${c(e)}): ${o||"(empty)"}`}))
|
|
193
|
-
return{content:[{type:"text",text:`Session ${e}: ${r.length} messages (compact; use select:N for one in full):\n\n${t.join("\n")}`}]}}const g=(e,t)=>{const n=[`[${t+1}] ${l(e)} (${c(e)}):`]
|
|
194
|
-
for(const t of e.parts)if("text"===t.type&&t.text)n.push(a(t.text,5e3))
|
|
195
|
-
else if("tool"===t.type){const e=t.state||{},s=u(e.output).replace(/\s+/g," ").trim()
|
|
196
|
-
n.push(`\u{1f527} ${t.tool||"tool"} [${e.status??"unknown"}]${s?` \u2192 ${a(s,200)}`:""}`)}return n.length>1?n.join("\n"):`${n[0]}\n(no content)`}
|
|
197
|
-
if(o?.latest){const t=e=>e.parts.some((e=>"text"===e.type&&e.text||"tool"===e.type))
|
|
198
|
-
let n=r.length-1
|
|
199
|
-
for(;n>0&&!t(r[n]);)n--
|
|
200
|
-
const s=r.length-1-n
|
|
201
|
-
return{content:[{type:"text",text:`Session ${e}: latest message${s>0?` (skipped ${s} trailing empty message${1===s?"":"s"}; use compact:true for the full trajectory)`:""}:\n\n${g(r[n],n)}`}]}}const p=r.map(((e,t)=>g(e,t))).join("\n\n---\n\n")
|
|
202
|
-
return{content:[{type:"text",text:`Session ${e}: last ${r.length} messages:\n\n${p}`}]}}catch(e){throw new Error(`Failed to read messages: ${(0,v.getErrorMessage)(e)}`)}}(d,o,t,l,{compact:n.compact,select:n.select,latest:s})
|
|
203
|
-
break}case"list-sessions":const e={activeOnly:n.activeOnly,requestId:n.requestId,limit:n.limit,minTokens:n.minTokens,maxTokens:n.maxTokens,maxAgeHours:n.maxAgeHours,parentSessionId:i?.sessionId}
|
|
204
|
-
g=await m(t,l,o,e)
|
|
205
|
-
break
|
|
206
|
-
default:throw new w.ValidationError(`Unknown operation: ${u}`)}c({success:!0}),s.incrementCounter(`subagent_operations_${u}_success`,1)
|
|
207
|
-
const p=E[u]
|
|
208
|
-
return p?(0,C.withAlchemyKind)(g,p):g}catch(e){return l.error("Subagent operations failed",{error:e instanceof Error?e.stack:String(e)}),c({success:!1}),s.incrementCounter("subagent_operations_errors",1),{content:[{type:"text",text:`Subagent operation failed: ${(0,v.getErrorMessage)(e)}`}],isError:!0}}}
|
|
209
|
-
const w=t(98547),$=t(3928),y=t(16714),S=t(49725),I=t(7451),b=t(87907),v=t(21319),k=t(79896),x=t(16928),A=t(97734),C=t(62263),E={spawn:"spawn-subagent",continue:"continue-subagent","check-status":"check-subagent-status",abort:"abort-subagent","read-messages":"read-subagent-messages","list-sessions":"list-subagent-sessions"},T="true"===process.env.ALCHEMY_DEBUG_LOGS,j=(0,t(53603).getActionServerPort)(),q=6e4,P=3e5,U=new Map},16714:(e,exports,t)=>{Object.defineProperty(exports,"__esModule",{value:!0}),exports.invalidateServerUrlCache=function(){s=null},exports.getServerUrl=async function(e,o){const i=process.env.OPENCODE_TUI_URL
|
|
210
|
-
if(s&&s.basePath===e.basePath&&s.envUrl===i)return s.result
|
|
211
|
-
let r=i
|
|
212
|
-
if(!r)try{const{readFileSync:n}=await Promise.resolve().then(t.t.bind(t,79896,23)),{join:s}=await Promise.resolve().then(t.t.bind(t,16928,23)),i=n(s(e.basePath,".alchemy_lab","opencode.json"),"utf8"),a=JSON.parse(i)
|
|
213
|
-
a.port&&(r=`http://127.0.0.1:${a.port}`,o.debug("Discovered OpenCode server URL from .alchemy_lab/opencode.json",{serverUrl:r}))}catch(e){o.debug("Could not read .alchemy_lab/opencode.json",{error:e instanceof Error?e.message:String(e)})}if(r)try{(0,n.noteServe)(Number(new URL(r).port),(0,n.currentServePassword)(e.basePath))}catch{}return s={basePath:e.basePath,envUrl:i,result:r},r}
|
|
214
|
-
const n=t(7245)
|
|
215
|
-
let s=null},24019:(e,exports,t)=>{exports.formatLiveWorker=function(e){const t=e.agentType?e.agentType:"worker",n=[],s=!0===e.busy?"mid-turn":!1===e.busy?"between turns":"unknown"
|
|
216
|
-
return n.push(`- ${t} (${e.sessionId}): ${e.status}, ${e.detail}; ${s}`),e.current&&n.push(` now: ${e.current}`),e.recent.length>0&&n.push(` recently: ${e.recent.join(", ")}`),e.lastSaid&&n.push(` last said${e.lastSaidAgo?` (${e.lastSaidAgo})`:""}: "${e.lastSaid}"`),e.lastRefusal&&n.push(` last refused (its tool said): ${e.lastRefusal}`),n.join("\n")},exports.readLiveWorker=async function(e,t){if(!e)return null
|
|
217
|
-
const i=t.filter((e=>(0,s.isWorkerAgentType)(e.agentType??""))),r=(i.length>0?i:t).slice(-1)[0]
|
|
218
|
-
if(!r)return null
|
|
219
|
-
const a=e.replace(/\/$/,"")
|
|
220
|
-
try{const[e,t,s]=await Promise.all([fetch(`${a}/session/${r.sessionId}`,{signal:AbortSignal.timeout(5e3)}),fetch(`${a}/session/${r.sessionId}/message?limit=60`,{signal:AbortSignal.timeout(8e3)}),fetch(`${a}/session/status`,{signal:AbortSignal.timeout(5e3)}).catch((()=>null))])
|
|
221
|
-
if(!e.ok||!t.ok)return null
|
|
222
|
-
const i=await e.json(),l=await t.json()
|
|
223
|
-
let c=null
|
|
224
|
-
if(s&&s.ok)try{const e=await s.json(),t=e?.[r.sessionId]
|
|
225
|
-
c=void 0!==t&&"busy"===("string"==typeof t?t:t?.type)}catch{}const d=(0,n.extractRecentActivity)(l),u=(0,n.deriveActivityStatus)(d.lastActivityTime,i.time?.updated??Date.now())
|
|
226
|
-
let g=null,p=null
|
|
227
|
-
for(let e=l.length-1;e>=0;e--){const t=l[e]
|
|
228
|
-
if("assistant"!==t.info.role)continue
|
|
229
|
-
const s=(t.parts??[]).filter((e=>"text"===e.type&&e.text)).map((e=>e.text)).join(" ").replace(/\s+/g," ").trim()
|
|
230
|
-
if(s){g=s.length>220?s.slice(0,217)+"...":s,p=(0,n.formatTimeSince)(Date.now()-(t.info.time.completed??t.info.time.created))
|
|
231
|
-
break}}const f=function(e){for(let t=e.length-1;t>=0;t--){const n=e[t]
|
|
232
|
-
if("user"===n.info.role)return null
|
|
233
|
-
const s=n.parts??[]
|
|
234
|
-
for(let e=s.length-1;e>=0;e--){const t=s[e]
|
|
235
|
-
if("tool"!==t.type)continue
|
|
236
|
-
const n="error"===t.state?.status?String(t.state?.error??""):"string"==typeof t.state?.output?t.state.output:""
|
|
237
|
-
if("error"===t.state?.status||o.test(n)){const e=String(t.tool??"tool").replace(/^alchemy_/,""),s=n.replace(/\s+/g," ").trim()
|
|
238
|
-
return`${e}: ${s.length>240?s.slice(0,237)+"...":s}`}}}return null}(l),h=function(e){for(let t=e.length-1;t>=0;t--){const n=e[t]?.info,s=n?.providerID??n?.model?.providerID
|
|
239
|
-
if("string"==typeof s&&s)return s}return null}(l)
|
|
240
|
-
return{sessionId:r.sessionId,agentType:r.agentType,busy:c,status:u.status,detail:u.detail,current:d.current,recent:d.recent,lastSaid:g,lastSaidAgo:p,lastRefusal:f,provider:h}}catch{return null}}
|
|
241
|
-
const n=t(16554),s=t(47221),o=/^\s*(?:Error:|\u26d4|\u274c|Not filed|Not started|Not kept|Cannot |STOP:)/},49725:(e,exports,t)=>{Object.defineProperty(exports,"__esModule",{value:!0}),exports.deliverToSession=async function(e,t,s={}){const o=s.noVerify?0:s.verifySeconds??20
|
|
242
|
-
try{const i=await fetch(`${(0,n.getActionServerBaseUrl)()}/api/sessions/${encodeURIComponent(e)}/deliver`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:t,kind:s.kind,partPayload:s.partPayload,noVerify:s.noVerify,verifySeconds:s.verifySeconds}),signal:AbortSignal.timeout(1e3*(o+25))}),r=await i.json().catch((()=>null))
|
|
243
|
-
return i.ok?r?.data??{ok:!1,error:"deliver_route",detail:"empty response"}:{ok:!1,error:"deliver_route",detail:r?.error||`HTTP ${i.status}`}}catch(e){return{ok:!1,error:"deliver_route",detail:e instanceof Error?e.message:String(e)}}},exports.deliveryFailureText=function(e,t){return`\u274c NOT delivered to session ${e}: ${t.detail||t.error||"unknown reason"}. The session did not receive this and nothing will act on it.`}
|
|
244
|
-
const n=t(53603)}}
|
package/dist/380.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
exports.id=380,exports.ids=[380],exports.modules={94380:function(e,exports,t){function r(e){return i.default.createHash("md5").update(e).digest("hex")}async function s(e){try{return r(await o.default.promises.readFile(e))}catch{return null}}var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
|
|
3
|
-
Object.defineProperty(exports,"__esModule",{value:!0}),exports.syncPluginsGlobal=async function(e,t,n){const i={synced:[],skipped:[],errors:[]},l=n||function(){const e=process.argv[1]
|
|
4
|
-
let t=e
|
|
5
|
-
try{t=o.default.realpathSync(e)}catch{}return a.default.dirname(t)}(),d=a.default.join((0,u.getGlobalConfigDir)(e),"plugin")
|
|
6
|
-
try{await o.default.promises.mkdir(d,{recursive:!0})}catch(e){return t.error("Failed to create global plugin directory",{destDir:d,error:e instanceof Error?e.message:"Unknown error"}),i}const f=a.default.join(d,"package.json"),p='{"type":"module"}\n'
|
|
7
|
-
try{await o.default.promises.readFile(f,"utf8").catch((()=>null))!==p&&await o.default.promises.writeFile(f,p,"utf8")}catch(e){t.warn("Failed to write global plugin package.json",{error:e instanceof Error?e.message:"Unknown error"})}for(const e of c){const n=a.default.join(l,e.sourceName),u=a.default.join(d,e.destName)
|
|
8
|
-
try{if(!o.default.existsSync(n)){t.warn(`Plugin source not found: ${e.sourceName}`,{sourcePath:n}),i.errors.push(e.destName)
|
|
9
|
-
continue}const a=await o.default.promises.readFile(n,"utf8").catch((()=>null))
|
|
10
|
-
if(null===a){t.warn(`Could not read plugin source: ${e.sourceName}`),i.errors.push(e.destName)
|
|
11
|
-
continue}const c=r(a),l=await s(u)
|
|
12
|
-
null===l||c!==l?(await o.default.promises.writeFile(u,a,"utf8"),t.info(`Synced plugin: ${e.destName}`,{destDir:d,reason:null===l?"not installed":"updated"}),i.synced.push(e.destName)):i.skipped.push(e.destName)}catch(r){t.error(`Failed to sync plugin: ${e.destName}`,{error:r instanceof Error?r.message:"Unknown error"}),i.errors.push(e.destName)}}return i.synced.length>0&&t.info("Synced global plugins",{destDir:d,synced:i.synced}),i},exports.cleanupLegacyProjectPlugins=async function(e,t){const r=a.default.join(e,".opencode","plugin"),s=[]
|
|
13
|
-
if(!o.default.existsSync(r))return{removed:s}
|
|
14
|
-
for(const e of l){const t=a.default.join(r,e)
|
|
15
|
-
if(o.default.existsSync(t))try{await o.default.promises.rm(t,{recursive:!0,force:!0}),s.push(e)}catch{}}s.length>0&&t.info("Removed legacy per-project plugin copies",{projectPluginDir:r,removed:s})
|
|
16
|
-
try{0===(await o.default.promises.readdir(r)).length&&await o.default.promises.rmdir(r)}catch{}return{removed:s}}
|
|
17
|
-
const o=n(t(79896)),a=n(t(16928)),i=n(t(76982)),u=t(41306),c=[{sourceName:"plugins/hooks/plugin.js",destName:"event-hooks.js"},{sourceName:"plugins/inject-session.js",destName:"inject-session.js"},{sourceName:"plugins/system-logger.js",destName:"system-logger.js"}],l=[...c.map((e=>e.destName)),"package.json","lib"]}}
|
package/dist/403.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
exports.id=403,exports.ids=[403],exports.modules={15403:(t,exports)=>{exports.formatCombinedOutput=function(t,e){const n=e.maxOut??o,u=t.length>n
|
|
3
|
-
return{output:u?"\u2026"+t.slice(-n):t,truncatedNote:u?`\n_(output truncated: view full with \`log:${e.invocationId}\`)_`:"",logFooter:`Log: \`log:${e.invocationId}\``}}
|
|
4
|
-
const o=3e3}}
|
package/dist/540.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
exports.id=540,exports.ids=[540],exports.modules={76390:(e,exports,t)=>{function r(...e){const t=(0,o.createHash)("sha256")
|
|
3
|
-
for(const r of e){const e=r??""
|
|
4
|
-
t.update(String(e.length)).update(":").update(e).update("\0")}return t.digest("hex")}function n(e,t=exports.SHORT_ADDRESS_LENGTH){return e.slice(0,t)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.SHORT_ADDRESS_LENGTH=void 0,exports.contentAddress=r,exports.shortAddress=n,exports.addressedName=function(e,...t){return`${e}-${n(r(...t))}`}
|
|
5
|
-
const o=t(76982)
|
|
6
|
-
exports.SHORT_ADDRESS_LENGTH=12},78540:(e,exports,t)=>{function r(e){const t=String(e??"").lastIndexOf("@")
|
|
7
|
-
return t>0?e.slice(0,t):String(e??"")}function n(e){const t=e.lastIndexOf("@"),n=t>0?e.slice(t+1):""
|
|
8
|
-
if(!n||!/^\d/.test(n))throw new Error(`"${e}" has no pinned version. A boxed connection installs once and reuses that build, so it needs an exact version, for example ${r(e)}@1.2.3.`)
|
|
9
|
-
return n}function o(e){return n(e),(0,m.addressedName)("alchemy-mcp-pkg",e)}function i(e,t){return(0,m.addressedName)("alchemy-mcp-state",e,t)}function a(e,t){return(0,m.addressedName)("alchemy-mcp-box",e,t)}function c(e,t,r,n){return`${(0,m.addressedName)("alchemy-mcp-repo",e,t,r,n)}:latest`}function s(e,t,r){return["docker","exec","-i",e,...t??[],...r??[]]}Object.defineProperty(exports,"__esModule",{value:!0}),exports.REGISTRY_ALLOWLIST=void 0,exports.packageNameOf=r,exports.assertPinned=n,exports.artifactVolumeFor=o,exports.stateVolumeFor=i,exports.boxNameFor=a,exports.prepareConnectionArtifact=async function(e,t){const r=String(e.packageSpec??"")
|
|
10
|
-
n(r)
|
|
11
|
-
const i=o(r)
|
|
12
|
-
if(await async function(e){return!!await(0,l.volumeExists)(e)&&0===(await(0,l.docker)(["run","--rm","-v",`${e}:/pkg:ro`,"alpine:3.20","test","-f",`/pkg/${k}`],l.DOCKER_OP_TIMEOUT_MS)).exit}(i))return t.info("MCP artifact already installed, reusing",{volume:i,package:r}),{ok:!0,volume:i}
|
|
13
|
-
const a=e.image??f,c=await(0,l.ensureImage)(a)
|
|
14
|
-
if(c)return{ok:!1,error:c}
|
|
15
|
-
const s=await(0,l.docker)(["run","--rm","-u","0","-v",`${i}:/pkg`,"alpine:3.20","sh","-c","touch /pkg/.owner && chown -R 1000:1000 /pkg"],l.DOCKER_OP_TIMEOUT_MS)
|
|
16
|
-
if(0!==s.exit)return{ok:!1,error:`could not prepare the artifact volume: ${(s.stderr||"").trim()}`}
|
|
17
|
-
const u=new d.EgressProxy(`mcp-pkg-${Date.now()}-${process.pid}`,exports.REGISTRY_ALLOWLIST,!1)
|
|
18
|
-
let m=[],h=[]
|
|
19
|
-
const w=await u.start().catch((e=>({ok:!1,error:String(e)})))
|
|
20
|
-
if(!w.ok||!w.network)return await u.stop().catch((()=>{})),{ok:!1,error:`could not start the registry proxy, refusing to install with open egress: ${w.error??"unknown"}`}
|
|
21
|
-
m=["--network",w.network],h=Object.entries(w.proxyEnv||{}).flatMap((([e,t])=>["-e",`${e}=${t}`])),t.info("Installing MCP connection artifact",{package:r,volume:i})
|
|
22
|
-
const x=await(0,l.docker)(["run","--rm","--label",g,"--user","1000:1000","--cap-drop","ALL","--security-opt","no-new-privileges","--read-only","--tmpfs","/tmp:rw,nosuid,nodev,exec,size=512m","--ipc","none","--memory","2g","--memory-swap","2g","--cpus","2","--pids-limit","512","-e","HOME=/tmp","-e","npm_config_cache=/tmp/.npm",...m,...h,"-v",`${i}:/pkg`,"-w","/pkg",a,"sh","-c",`npm install --no-audit --no-fund --no-package-lock ${r} && touch /pkg/${k}`],p)
|
|
23
|
-
return await u.stop().catch((()=>{})),0!==x.exit?{ok:!1,error:`install failed: ${(x.stderr||x.stdout||`exit ${x.exit}`).trim().slice(0,400)}`}:(t.info("MCP connection artifact installed",{package:r,volume:i}),{ok:!0,volume:i})},exports.ensureConnectionBox=async function(e,t,r){const n=a(e.projectId,e.name),o=i(e.projectId,e.name),c=e.image??f,s=await(0,l.docker)(["inspect","-f",'{{.State.Running}} {{index .Config.Labels "alchemy.image"}}',n],l.DOCKER_OP_TIMEOUT_MS)
|
|
24
|
-
if(0===s.exit){const[e,t]=s.stdout.trim().split(/\s+/,2)
|
|
25
|
-
if("true"===e&&(t??"")===c)return{ok:!0,box:n}
|
|
26
|
-
"true"===e&&r.info("MCP connection box holds another image, replacing it",{box:n,was:t,now:c}),await(0,l.docker)(["rm","-f",n],l.DOCKER_OP_TIMEOUT_MS)}const d=null===t?void 0:await(0,l.ensureImage)(c)
|
|
27
|
-
if(d)return{ok:!1,error:d}
|
|
28
|
-
const m=await(0,l.docker)(["run","--rm","-u","0","-v",`${o}:/state`,"alpine:3.20","sh","-c","touch /state/.owner && chown -R 1000:1000 /state"],l.DOCKER_OP_TIMEOUT_MS)
|
|
29
|
-
if(0!==m.exit)return{ok:!1,error:`could not prepare the state volume: ${(m.stderr||"").trim()}`}
|
|
30
|
-
const p=Object.entries(e.environment??{}).flatMap((([e,t])=>["-e",`${e}=${t}`])),k=await(0,l.docker)(["create","--name",n,"--label",g,"--label",`alchemy.project=${e.projectId}`,"--label",`alchemy.image=${c}`,"--label",`alchemy.connection=${e.name}`,...(0,u.hardenedCreateArgs)({network:(h=e.egress,"open"===h?"bridge":"none"),user:"1000:1000",memory:"1g",cpus:1,pidsLimit:256,...null===t?{extraTmpfs:["/scratch:rw,nosuid,nodev,size=1g"]}:{}}),...p,...null===t?[]:["-v",`${t}:/pkg:ro`],...null===t?["--entrypoint","tail"]:[],"-v",`${o}:/state`,...e.worktreePath?["-v",`${e.worktreePath}:/work:ro`,"-w","/work"]:["-w","/state"],c,...null===t?["-f","/dev/null"]:["tail","-f","/dev/null"]],l.DOCKER_OP_TIMEOUT_MS)
|
|
31
|
-
var h
|
|
32
|
-
if(0!==k.exit)return{ok:!1,error:`could not create the box: ${(k.stderr||"").trim()}`}
|
|
33
|
-
const w=await(0,l.docker)(["start",n],l.DOCKER_OP_TIMEOUT_MS)
|
|
34
|
-
return 0!==w.exit?(await(0,l.docker)(["rm","-f",n],l.DOCKER_OP_TIMEOUT_MS),{ok:!1,error:`could not start the box: ${(w.stderr||"").trim()}`}):(r.info("MCP connection box up",{box:n,image:c,package:e.packageSpec??null,egress:e.egress??"none"}),{ok:!0,box:n})},exports.boxedCommand=function(e,t){return["docker","exec","-i",e,"node",`/pkg/node_modules/.bin/${t}`]},exports.repoImageTagFor=c,exports.prepareRepoImage=async function(e,t){const r=c(e.projectId,e.name,e.dockerfile,e.treeHash),n=await(0,l.docker)(["image","inspect",r],l.DOCKER_OP_TIMEOUT_MS)
|
|
35
|
-
if(n.spawnError)return{ok:!1,error:n.spawnError}
|
|
36
|
-
if(0===n.exit)return{ok:!0,image:r}
|
|
37
|
-
const o=e.context?.trim()||"."
|
|
38
|
-
t.info("Building MCP connection image from the repository",{name:e.name,dockerfile:e.dockerfile,context:o,tree:e.treeHash.slice(0,12),image:r})
|
|
39
|
-
const i=await(0,l.docker)(["build","-f",`${e.projectPath}/${e.dockerfile}`,"-t",r,`${e.projectPath}/${o}`],h)
|
|
40
|
-
if(0!==i.exit){const t=(i.stderr||i.stdout||`exit ${i.exit}`).trim().split("\n").slice(-6).join("\n")
|
|
41
|
-
return{ok:!1,error:`docker build of ${e.dockerfile} failed: ${t.slice(0,600)}`}}return t.info("MCP connection image built",{name:e.name,image:r}),{ok:!0,image:r}},exports.execCommandFromImageConfig=s,exports.repoCommand=async function(e,t){const r=await(0,l.docker)(["image","inspect","-f","{{json .Config.Entrypoint}}\n{{json .Config.Cmd}}",t],l.DOCKER_OP_TIMEOUT_MS)
|
|
42
|
-
if(0!==r.exit)return{ok:!1,error:`could not read the image's entrypoint: ${(r.stderr||"").trim()}`}
|
|
43
|
-
const[n,o]=r.stdout.trim().split("\n"),i=e=>{try{const t=JSON.parse(e??"null")
|
|
44
|
-
return Array.isArray(t)?t:null}catch{return null}},a=s(e,i(n),i(o))
|
|
45
|
-
return a.length<=4?{ok:!1,error:"the image has no ENTRYPOINT or CMD, so there is nothing to run; give the Dockerfile one that starts the MCP server on stdio"}:{ok:!0,command:a}},exports.removeConnectionBox=async function(e,t){await(0,l.docker)(["rm","-f",a(e,t)],l.DOCKER_OP_TIMEOUT_MS).catch((()=>{}))},exports.explainDerivedCommand=async function(e,r=8e3){const{spawn:n}=await Promise.resolve().then(t.t.bind(t,35317,23))
|
|
46
|
-
return await new Promise((t=>{let o="",i=!1
|
|
47
|
-
const a=e=>{i||(i=!0,t(e))}
|
|
48
|
-
try{const t=n(e[0],e.slice(1),{stdio:["ignore","pipe","pipe"]}),i=e=>{o=(o+e.toString("utf8")).slice(-2e3)}
|
|
49
|
-
t.stdout?.on("data",i),t.stderr?.on("data",i)
|
|
50
|
-
const c=setTimeout((()=>{try{t.kill("SIGKILL")}catch{}a("")}),r)
|
|
51
|
-
t.on("error",(e=>{clearTimeout(c),a(String(e.message??e))})),t.on("close",(e=>{clearTimeout(c)
|
|
52
|
-
const t=o.trim().split("\n").filter(Boolean).slice(-4).join("\n")
|
|
53
|
-
a(t?`exit ${e}: ${t}`:0===e?"":`exit ${e} with no output`)}))}catch(e){a(String(e?.message??e))}}))}
|
|
54
|
-
const l=t(6175),u=t(53157),d=t(79242),m=t(76390),p=3e5,f="node:20-alpine",g="alchemy.mcp=connection"
|
|
55
|
-
exports.REGISTRY_ALLOWLIST=["registry.npmjs.org","npmjs.org","npmjs.com"]
|
|
56
|
-
const k=".alchemy-install-complete",h=12e5}}
|
package/dist/603.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
exports.id=603,exports.ids=[603],exports.modules={53603:(t,exports,e)=>{function r(){return process.env.ALCHEMY_PROJECT_PATH||process.cwd()}function n(t){const e=Date.now(),n=!t
|
|
3
|
-
if(n&&null!==y&&e-v<g)return y
|
|
4
|
-
const o=(0,l.join)(t||r(),h,d)
|
|
5
|
-
if((0,a.existsSync)(o))try{const t=(0,a.readFileSync)(o,"utf-8"),r=JSON.parse(t)
|
|
6
|
-
if("number"==typeof r.port&&r.port>0&&r.port<65536)return n&&(y=r.port,v=e),r.port}catch{}return n&&(y=f,v=e),f}function o(t){return t||r()}async function c(t){try{const e=await(0,p.fetch)(`http://localhost:${t}/health`,{signal:AbortSignal.timeout(1500)})
|
|
7
|
-
if(!e.ok)return null
|
|
8
|
-
const r=await e.json()
|
|
9
|
-
return"string"==typeof r?.projectPath?r.projectPath:null}catch{return null}}async function s(t){const e=o(t),r=Date.now(),s=w.get(e)
|
|
10
|
-
if(s&&r-s.at<S)return s.port
|
|
11
|
-
for(const o of[0,1]){1===o&&(y=null,v=0)
|
|
12
|
-
const s=n(t),u=await c(s)
|
|
13
|
-
if(u&&i(u)===i(e))return w.set(e,{port:s,at:r}),s}return w.delete(e),null}function i(t){try{return(0,a.realpathSync)(t)}catch{return t}}function u(){const t=Date.now()
|
|
14
|
-
return t-m>S&&(m=t,s().then((t=>{null===t&&(y=null,v=0,console.error(`[alchemy] the recorded action-server port does not serve ${o()}: re-reading it. If this repeats, the server for this project is not running.`))})).catch((()=>{}))),`http://localhost:${n()}`}Object.defineProperty(exports,"__esModule",{value:!0}),exports.getActionServerPort=n,exports.verifiedActionServerPort=s,exports.getActionServerBaseUrl=u,exports.actionServerFetch=function(t,e){return j||(j=new p.Agent({headersTimeout:0,bodyTimeout:0})),(0,p.fetch)(`${u()}${t}`,{...e,dispatcher:j})}
|
|
15
|
-
const a=e(79896),l=e(16928),p=e(9956),f=3456,h=".alchemy_lab",d="action-server.json"
|
|
16
|
-
let y=null,v=0
|
|
17
|
-
const g=5e3,w=new Map,S=3e4
|
|
18
|
-
let j,m=0}}
|
package/dist/674.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
exports.id=674,exports.ids=[674],exports.modules={75674:(e,exports,t)=>{async function o(e,t){if(t){if(!n||Date.now()-n.at>i)try{const t=await e.apiClient.get(`/api/projects/${e.projectId}/session-request-associations?activeOnly=true&limit=500`),o=t?.data??t??[],r=new Map
|
|
3
|
-
for(const e of o)e?.opencodeSessionId&&e?.requestLocalId&&r.set(e.opencodeSessionId,e.requestLocalId)
|
|
4
|
-
n={at:Date.now(),bySession:r}}catch(t){e.logger.debug?.("MCP receipt: could not read associations",{error:(0,r.getErrorMessage)(t)}),n=n??{at:Date.now(),bySession:new Map}}return n.bySession.get(t)}}exports.requestForSession=o,exports.openMcpReceipt=async function(e,t){const n=await o(e,t.sessionId??""),i=t.target?` (${t.target})`:"",c=`${t.tool} on the "${t.connection}" MCP server${i}`,d=t.allowed?`Called ${c}`:`Did not run ${c}: ${t.reason}`,l={connection:t.connection,tool:t.tool,target:t.target??null,gate:t.verdict,status:t.allowed?"started":"refused",sessionId:t.sessionId??null,callId:t.callId??null,startedAt:(new Date).toISOString()}
|
|
5
|
-
try{const o=await e.apiClient.post(`/api/projects/${e.projectId}/tool-records`,{...n?{requestId:n}:{},type:"mcp-call",...t.sessionId?{cliOrigin:{providerId:"opencode",sessionId:t.sessionId,createdAt:(new Date).toISOString()}}:{},metadata:l,note:d}),r=o?.data?.id??o?.id
|
|
6
|
-
t.allowed&&t.callId&&r&&(s.set(t.callId,{recordId:String(r),startedAt:Date.now(),metadata:l}),function(){if(s.size<=a)return
|
|
7
|
-
const e=[...s.entries()].sort(((e,t)=>e[1].startedAt-t[1].startedAt))
|
|
8
|
-
for(const[t]of e){if(s.size<=a)break
|
|
9
|
-
s.delete(t)}}())}catch(o){e.logger.error("MCP receipt could not be written",{connection:t.connection,tool:t.tool,error:(0,r.getErrorMessage)(o)})}},exports.recordIdForCall=function(e){if(e)return s.get(e)?.recordId},exports.closeMcpReceipt=async function(e,t){if(!t.callId)return
|
|
10
|
-
let o=s.get(t.callId)
|
|
11
|
-
if(o||(await new Promise((e=>setTimeout(e,250))),o=s.get(t.callId)),o){s.delete(t.callId)
|
|
12
|
-
try{await e.apiClient.patch(`/api/projects/${e.projectId}/tool-records/${o.recordId}`,{metadata:{...o.metadata,status:t.ok?"completed":"failed",durationMs:Date.now()-o.startedAt,finishedAt:(new Date).toISOString(),...t.outputPreview?{outputPreview:t.outputPreview.slice(0,500)}:{},...t.error?{error:String(t.error).slice(0,500)}:{}}})}catch(o){e.logger.warn("MCP receipt could not be closed",{callId:t.callId,error:(0,r.getErrorMessage)(o)})}}}
|
|
13
|
-
const r=t(21319),s=new Map,a=500
|
|
14
|
-
let n=null
|
|
15
|
-
const i=3e4}}
|
package/dist/796.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
exports.id=796,exports.ids=[796],exports.modules={68796:(e,exports,t)=>{async function n(e){if(p&&Date.now()-p.at<d)return p.servers
|
|
3
|
-
try{const t=await e.apiClient.get(`/api/projects/${e.projectId}/mcp-servers`),n=t?.data??t??[]
|
|
4
|
-
if(Array.isArray(n))return p={at:Date.now(),servers:n},n}catch(t){e.logger.warn("MCP gate: could not read the registry",{error:(0,c.getErrorMessage)(t)})}return p?.servers??[]}function r(e){return e.filter((e=>e.enabled)).map((e=>e.name))}function o(e,t){const n=[...t].sort(((e,t)=>t.length-e.length))
|
|
5
|
-
for(const t of n){const n=`${t}_`
|
|
6
|
-
if(e.startsWith(n)&&e.length>n.length)return{server:t,tool:e.slice(n.length)}}return null}function s(e,t=200){if(!e||"object"!=typeof e||Array.isArray(e))return""
|
|
7
|
-
const n=Object.entries(e)
|
|
8
|
-
if(0===n.length)return""
|
|
9
|
-
const r=e=>{const t=u.indexOf(e)
|
|
10
|
-
return-1===t?u.length:t}
|
|
11
|
-
n.sort(((e,t)=>r(e[0])-r(t[0])))
|
|
12
|
-
const o=[]
|
|
13
|
-
for(const[e,t]of n){if(o.length>=4)break
|
|
14
|
-
let n
|
|
15
|
-
if("string"==typeof t)n=t.length>80?`${t.length} characters`:t
|
|
16
|
-
else if("number"==typeof t||"boolean"==typeof t)n=String(t)
|
|
17
|
-
else if(Array.isArray(t)){const e=t.filter((e=>"string"==typeof e))
|
|
18
|
-
n=e.length===t.length&&e.join(", ").length<=80?e.join(", "):`${t.length} items`}else{if(null==t)continue
|
|
19
|
-
n="an object"}o.push(`${e}: ${n}`)}const s=o.join(", ")
|
|
20
|
-
return s.length>t?`${s.slice(0,t-1)}\u2026`:s}function i(e,t,n,r){const o=[`Let an agent run ${t} on "${e}", an MCP server this project is connected to?`],i=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return""
|
|
21
|
-
const t=s(e,400).split(", ").map((e=>{const t=e.indexOf(": ")
|
|
22
|
-
return-1===t?null:[e.slice(0,t),e.slice(t+2)]})).filter(Boolean)
|
|
23
|
-
if(0===t.length)return""
|
|
24
|
-
const n=Math.max(...t.map((([e])=>e.length)))
|
|
25
|
-
return t.map((([e,t])=>` ${e.padEnd(n)} ${t}`)).join("\n")}(r)
|
|
26
|
-
i&&o.push(i)
|
|
27
|
-
const a=n?`This runs inside "${e}", not in this project. The server's own note on ${t}: ${function(e,t=220){const n=e.trim().replace(/\s+/g," ")
|
|
28
|
-
if(n.length<=t)return n
|
|
29
|
-
const r=n.slice(0,t),o=Math.max(r.lastIndexOf(". "),r.lastIndexOf("! "),r.lastIndexOf("? "))
|
|
30
|
-
if(o>.4*t)return r.slice(0,o+1)
|
|
31
|
-
const s=r.lastIndexOf(" ")
|
|
32
|
-
return`${r.slice(0,s>0?s:t)}\u2026`}(n)}`:`This runs inside "${e}", not in this project, and the server does not say what ${t} does.`
|
|
33
|
-
return o.push(a),o.join("\n\n")}exports.invalidateMcpRegistry=function(){p=null},exports.getRegisteredMcpServers=n,exports.gatedNamespaces=r,exports.splitToolKey=o,exports.summariseArgs=s,exports.gateMcpCall=async function(e,c){const d=await n(e),p=o(c.toolName,r(d))
|
|
34
|
-
if(!p)return{allow:!0,verdict:"not-external",reason:"Not a registered MCP connection tool"}
|
|
35
|
-
const u=d.find((e=>e.name===p.server))
|
|
36
|
-
if(!u||!u.enabled)return{allow:!1,verdict:"unknown-connection",reason:`the MCP server "${p.server}" is not enabled for this project`}
|
|
37
|
-
if(function(e,t){const n=e?.find((e=>e.name===t))
|
|
38
|
-
return!0===n?.readOnly}(u.toolManifest,p.tool))return{allow:!0,verdict:"read-only",reason:`the ${p.server} MCP server marks ${p.tool} read-only`}
|
|
39
|
-
const{requestForSession:f}=await t.e(674).then(t.bind(t,75674)),h=c.sessionId?await f(e,c.sessionId):void 0,g=h??c.sessionId,v=g?`mcp:${p.server}:${g}`:`mcp:${p.server}`,y=s(c.args),$=y?`MCP ${p.server} \xb7 ${p.tool} (${y})`:`MCP ${p.server} \xb7 ${p.tool}`,m=u.toolManifest?.find((e=>e.name===p.tool))?.description
|
|
40
|
-
if((0,a.isSessionAllowed)(v))return{allow:!0,verdict:"session-allowed",reason:h?`already allowed for ${h}`:"already allowed for this run"}
|
|
41
|
-
const{id:w,promise:b,created:j}=(0,a.createApproval)(v,$)
|
|
42
|
-
w&&j&&c.sessionId&&(0,l.bridgeApprovalToNotification)(e.apiClient,e.projectId,{approvalId:w,approvalKey:v,sessionId:c.sessionId,command:$,question:i(p.server,p.tool,m,c.args),approveOption:{description:`Run it once, in "${p.server}"`},denyOption:{description:"Do not run it; the agent is told it was declined"},allowSessionOption:h?{label:`Allow for the rest of ${h}`,description:`Run it, and stop asking about "${p.server}" for the rest of this request`}:{label:"Allow while this agent keeps working",description:`Run it, and stop asking about "${p.server}" until this agent finishes`}})
|
|
43
|
-
const M=await b
|
|
44
|
-
return"deny"===M?{allow:!1,verdict:"denied",reason:"a person declined it"}:"timeout"===M?{allow:!1,verdict:"timeout",reason:"nobody answered the approval in time"}:{allow:!0,verdict:"approved",reason:"a person approved it"}}
|
|
45
|
-
const a=t(70799),l=t(36993),c=t(21319),d=3e4
|
|
46
|
-
let p=null
|
|
47
|
-
const u=["path","file","filename","file_path","filePath","paths","url","uri","endpoint","repo","repository","branch","id","key","name","title","query","q","command","sql","table"]}}
|