@shawnstack/quickforge 1.3.24 → 1.3.25

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.
Files changed (45) hide show
  1. package/README.md +14 -14
  2. package/dist/assets/anthropic-B1_Yrokl.js +39 -0
  3. package/dist/assets/azure-openai-responses-UMiOBCBd.js +1 -0
  4. package/dist/assets/google-BLE_Gcd1.js +1 -0
  5. package/dist/assets/google-shared-Cqjw1plk.js +11 -0
  6. package/dist/assets/google-vertex-6_sIZLVc.js +1 -0
  7. package/dist/assets/{icons-DmRYmmql.js → icons-Bs7OG8yi.js} +1 -1
  8. package/dist/assets/{index-s72bxhrh.js → index-C3bc5C3k.js} +550 -544
  9. package/dist/assets/index-C7oT9Rdw.css +3 -0
  10. package/dist/assets/{mistral-DCZ8VphX.js → mistral-DmZEmRkv.js} +1 -1
  11. package/dist/assets/openai-codex-responses-i_SmQGzQ.js +7 -0
  12. package/dist/assets/openai-completions-BmmZFDDY.js +5 -0
  13. package/dist/assets/openai-prompt-cache-CErE62Yt.js +1 -0
  14. package/dist/assets/openai-responses-C8tPdeE9.js +1 -0
  15. package/dist/assets/{openai-responses-shared-RzgnIlMf.js → openai-responses-shared-DchtjQNp.js} +1 -1
  16. package/dist/assets/openrouter-CcTv1G_v.js +1 -0
  17. package/dist/assets/{react-vendor-BsV2HYbc.js → react-vendor-Cu-7p9CI.js} +1 -1
  18. package/dist/assets/sanitize-unicode-BhyPmlyt.js +1 -0
  19. package/dist/assets/transform-messages-Dhj_4OTw.js +1 -0
  20. package/dist/index.html +4 -4
  21. package/package.json +3 -3
  22. package/server/agent-manager.mjs +66 -160
  23. package/server/ai-http-logger.mjs +20 -5
  24. package/server/approval-store.mjs +63 -0
  25. package/server/message-converters.mjs +79 -0
  26. package/server/routes/agent-profiles.mjs +1 -1
  27. package/server/routes/filesystem.mjs +18 -2
  28. package/server/routes/scheduled-tasks.mjs +1 -1
  29. package/server/routes/storage.mjs +66 -31
  30. package/server/session-utils.mjs +1 -1
  31. package/server/storage.mjs +78 -2
  32. package/server/tool-wiring.mjs +87 -0
  33. package/server/utils/workspace.mjs +20 -1
  34. package/dist/assets/anthropic-BrbLtQkg.js +0 -39
  35. package/dist/assets/azure-openai-responses-q9QFpQk3.js +0 -1
  36. package/dist/assets/google-Bv6IeSRf.js +0 -1
  37. package/dist/assets/google-shared-CLc4ziON.js +0 -11
  38. package/dist/assets/google-vertex-Cwpe8vbn.js +0 -1
  39. package/dist/assets/index-C4m48ndP.css +0 -3
  40. package/dist/assets/openai-codex-responses-Bx7iyHzd.js +0 -7
  41. package/dist/assets/openai-completions-CihVV11E.js +0 -5
  42. package/dist/assets/openai-responses-BigEdUNS.js +0 -1
  43. package/dist/assets/transform-messages-CmnxG9RB.js +0 -1
  44. /package/dist/assets/{hash-Bt1aVMQ3.js → hash-kZ2KD_no.js} +0 -0
  45. /package/dist/assets/{openai-Cn7eGqwa.js → openai-Bf1npfRy.js} +0 -0
@@ -1,4 +1,4 @@
1
- import{l as e,r as t}from"./index-s72bxhrh.js";import{i as n,t as r}from"./transform-messages-CmnxG9RB.js";import{t as i}from"./hash-Bt1aVMQ3.js";function a(e,t){let n={v:1,id:e};return t&&(n.phase=t),JSON.stringify(n)}function o(e){if(e){if(e.startsWith(`{`))try{let t=JSON.parse(e);if(t.v===1&&typeof t.id==`string`)return t.phase===`commentary`||t.phase===`final_answer`?{id:t.id,phase:t.phase}:{id:t.id}}catch{}return{id:e}}}function s(e,t,a,s){let c=[],l=e=>{let t=e.replace(/[^a-zA-Z0-9_-]/g,`_`);return(t.length>64?t.slice(0,64):t).replace(/_+$/,``)},u=e=>{let t=`fc_${i(e)}`;return t.length>64?t.slice(0,64):t},d=r(t.messages,e,(t,n,r)=>{if(!a.has(e.provider)||!t.includes(`|`))return l(t);let[i,o]=t.split(`|`),s=l(i),c=r.provider!==e.provider||r.api!==e.api?u(o):l(o);return c.startsWith(`fc_`)||(c=l(`fc_${c}`)),`${s}|${c}`});if((s?.includeSystemPrompt??!0)&&t.systemPrompt){let r=e.reasoning?`developer`:`system`;c.push({role:r,content:n(t.systemPrompt)})}let f=0;for(let t of d){if(t.role===`user`)if(typeof t.content==`string`)c.push({role:`user`,content:[{type:`input_text`,text:n(t.content)}]});else{let e=t.content.map(e=>e.type===`text`?{type:`input_text`,text:n(e.text)}:{type:`input_image`,detail:`auto`,image_url:`data:${e.mimeType};base64,${e.data}`});if(e.length===0)continue;c.push({role:`user`,content:e})}else if(t.role===`assistant`){let r=[],a=t,s=a.model!==e.id&&a.provider===e.provider&&a.api===e.api;for(let e of t.content)if(e.type===`thinking`){if(e.thinkingSignature){let t=JSON.parse(e.thinkingSignature);r.push(t)}}else if(e.type===`text`){let t=e,a=o(t.textSignature),s=a?.id;s?s.length>64&&(s=`msg_${i(s)}`):s=`msg_${f}`,r.push({type:`message`,role:`assistant`,content:[{type:`output_text`,text:n(t.text),annotations:[]}],status:`completed`,id:s,phase:a?.phase})}else if(e.type===`toolCall`){let t=e,[n,i]=t.id.split(`|`),a=i;s&&a?.startsWith(`fc_`)&&(a=void 0),r.push({type:`function_call`,id:a,call_id:n,name:t.name,arguments:JSON.stringify(t.arguments)})}if(r.length===0)continue;c.push(...r)}else if(t.role===`toolResult`){let r=t.content.filter(e=>e.type===`text`).map(e=>e.text).join(`
1
+ import{l as e,r as t}from"./index-C3bc5C3k.js";import{t as n}from"./sanitize-unicode-BhyPmlyt.js";import{t as r}from"./transform-messages-Dhj_4OTw.js";import{t as i}from"./hash-kZ2KD_no.js";function a(e,t){let n={v:1,id:e};return t&&(n.phase=t),JSON.stringify(n)}function o(e){if(e){if(e.startsWith(`{`))try{let t=JSON.parse(e);if(t.v===1&&typeof t.id==`string`)return t.phase===`commentary`||t.phase===`final_answer`?{id:t.id,phase:t.phase}:{id:t.id}}catch{}return{id:e}}}function s(e,t,a,s){let c=[],l=e=>{let t=e.replace(/[^a-zA-Z0-9_-]/g,`_`);return(t.length>64?t.slice(0,64):t).replace(/_+$/,``)},u=e=>{let t=`fc_${i(e)}`;return t.length>64?t.slice(0,64):t},d=r(t.messages,e,(t,n,r)=>{if(!a.has(e.provider)||!t.includes(`|`))return l(t);let[i,o]=t.split(`|`),s=l(i),c=r.provider!==e.provider||r.api!==e.api?u(o):l(o);return c.startsWith(`fc_`)||(c=l(`fc_${c}`)),`${s}|${c}`});if((s?.includeSystemPrompt??!0)&&t.systemPrompt){let r=e.reasoning?`developer`:`system`;c.push({role:r,content:n(t.systemPrompt)})}let f=0;for(let t of d){if(t.role===`user`)if(typeof t.content==`string`)c.push({role:`user`,content:[{type:`input_text`,text:n(t.content)}]});else{let e=t.content.map(e=>e.type===`text`?{type:`input_text`,text:n(e.text)}:{type:`input_image`,detail:`auto`,image_url:`data:${e.mimeType};base64,${e.data}`});if(e.length===0)continue;c.push({role:`user`,content:e})}else if(t.role===`assistant`){let r=[],a=t,s=a.model!==e.id&&a.provider===e.provider&&a.api===e.api;for(let e of t.content)if(e.type===`thinking`){if(e.thinkingSignature){let t=JSON.parse(e.thinkingSignature);r.push(t)}}else if(e.type===`text`){let t=e,a=o(t.textSignature),s=a?.id;s?s.length>64&&(s=`msg_${i(s)}`):s=`msg_${f}`,r.push({type:`message`,role:`assistant`,content:[{type:`output_text`,text:n(t.text),annotations:[]}],status:`completed`,id:s,phase:a?.phase})}else if(e.type===`toolCall`){let t=e,[n,i]=t.id.split(`|`),a=i;s&&a?.startsWith(`fc_`)&&(a=void 0),r.push({type:`function_call`,id:a,call_id:n,name:t.name,arguments:JSON.stringify(t.arguments)})}if(r.length===0)continue;c.push(...r)}else if(t.role===`toolResult`){let r=t.content.filter(e=>e.type===`text`).map(e=>e.text).join(`
2
2
  `),i=t.content.some(e=>e.type===`image`),a=r.length>0,[o]=t.toolCallId.split(`|`),s;if(i&&e.input.includes(`image`)){let e=[];a&&e.push({type:`input_text`,text:n(r)});for(let n of t.content)n.type===`image`&&e.push({type:`input_image`,detail:`auto`,image_url:`data:${n.mimeType};base64,${n.data}`});s=e}else s=n(a?r:`(see attached image)`);c.push({type:`function_call_output`,call_id:o,output:s})}f++}return c}function c(e,t){let n=t?.strict===void 0?!1:t.strict;return e.map(e=>({type:`function`,name:e.name,description:e.description,parameters:e.parameters,strict:n}))}async function l(n,r,i,o,s){let c=null,l=null,d=r.content,f=()=>d.length-1;for await(let d of n)if(d.type===`response.created`)r.responseId=d.response.id;else if(d.type===`response.output_item.added`){let e=d.item;e.type===`reasoning`?(c=e,l={type:`thinking`,thinking:``},r.content.push(l),i.push({type:`thinking_start`,contentIndex:f(),partial:r})):e.type===`message`?(c=e,l={type:`text`,text:``},r.content.push(l),i.push({type:`text_start`,contentIndex:f(),partial:r})):e.type===`function_call`&&(c=e,l={type:`toolCall`,id:`${e.call_id}|${e.id}`,name:e.name,arguments:{},partialJson:e.arguments||``},r.content.push(l),i.push({type:`toolcall_start`,contentIndex:f(),partial:r}))}else if(d.type===`response.reasoning_summary_part.added`)c&&c.type===`reasoning`&&(c.summary=c.summary||[],c.summary.push(d.part));else if(d.type===`response.reasoning_summary_text.delta`){if(c?.type===`reasoning`&&l?.type===`thinking`){c.summary=c.summary||[];let e=c.summary[c.summary.length-1];e&&(l.thinking+=d.delta,e.text+=d.delta,i.push({type:`thinking_delta`,contentIndex:f(),delta:d.delta,partial:r}))}}else if(d.type===`response.reasoning_summary_part.done`){if(c?.type===`reasoning`&&l?.type===`thinking`){c.summary=c.summary||[];let e=c.summary[c.summary.length-1];e&&(l.thinking+=`
3
3
 
4
4
  `,e.text+=`
@@ -0,0 +1 @@
1
+ import{d as e}from"./index-C3bc5C3k.js";import{t}from"./headers-5EYI0_pl.js";import{t as n}from"./sanitize-unicode-BhyPmlyt.js";import{n as r}from"./openai-Bf1npfRy.js";var i=async(n,r,i)=>{let c={api:n.api,provider:n.provider,model:n.id,output:[],stopReason:`stop`,timestamp:Date.now()};try{let l=i?.apiKey||e(n.provider);if(!l)throw Error(`No API key available for provider: ${n.provider}`);let u=a(n,l,i?.headers),d=o(n,r),f=await i?.onPayload?.(d,n);f!==void 0&&(d=f);let p={...i?.signal?{signal:i.signal}:{},...i?.timeoutMs===void 0?{}:{timeout:i.timeoutMs},...i?.maxRetries===void 0?{}:{maxRetries:i.maxRetries}},{data:m,response:h}=await u.chat.completions.create(d,p).withResponse();await i?.onResponse?.({status:h.status,headers:t(h.headers)},n);let g=m;c.responseId=g.id,g.usage&&(c.usage=s(g.usage,n));let _=g.choices[0];if(_){let e=_.message.content;typeof e==`string`&&e.length>0&&c.output.push({type:`text`,text:e});for(let e of _.message.images??[]){let t=typeof e.image_url==`string`?e.image_url:e.image_url?.url;if(!t?.startsWith(`data:`))continue;let n=t.match(/^data:([^;]+);base64,(.+)$/);n&&c.output.push({type:`image`,mimeType:n[1],data:n[2]})}}return c}catch(e){return c.stopReason=i?.signal?.aborted?`aborted`:`error`,c.errorMessage=e instanceof Error?e.message:JSON.stringify(e),c}};function a(e,t,n){return new r({apiKey:t,baseURL:e.baseUrl,dangerouslyAllowBrowser:!0,defaultHeaders:{...e.headers,...n}})}function o(e,t){let r=t.input.map(e=>e.type===`text`?{type:`text`,text:n(e.text)}:{type:`image_url`,image_url:{url:`data:${e.mimeType};base64,${e.data}`}});return{model:e.id,messages:[{role:`user`,content:r}],stream:!1,modalities:e.output.includes(`text`)?[`image`,`text`]:[`image`]}}function s(e,t){let n=e.prompt_tokens||0,r=e.prompt_tokens_details?.cached_tokens||0,i=e.prompt_tokens_details?.cache_write_tokens||0,a=i>0?Math.max(0,r-i):r,o=Math.max(0,n-a-i),s=e.completion_tokens||0,c={input:o,output:s,cacheRead:a,cacheWrite:i,totalTokens:o+s+a+i,cost:{input:t.cost.input/1e6*o,output:t.cost.output/1e6*s,cacheRead:t.cost.cacheRead/1e6*a,cacheWrite:t.cost.cacheWrite/1e6*i,total:0}};return c.cost.total=c.cost.input+c.cost.output+c.cost.cacheRead+c.cost.cacheWrite,c}export{i as generateImagesOpenRouter};
@@ -1,4 +1,4 @@
1
- import{t as e}from"./rolldown-runtime-CkqCuyE9.js";import{Z as t}from"./icons-DmRYmmql.js";var n=e((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0<n;){var r=n-1>>>1,a=e[r];if(0<i(a,t))e[r]=t,e[n]=a,n=r;else break a}}function n(e){return e.length===0?null:e[0]}function r(e){if(e.length===0)return null;var t=e[0],n=e.pop();if(n!==t){e[0]=n;a:for(var r=0,a=e.length,o=a>>>1;r<o;){var s=2*(r+1)-1,c=e[s],l=s+1,u=e[l];if(0>i(c,n))l<a&&0>i(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(l<a&&0>i(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,D());else{var t=n(l);t!==null&&A(x,t.startTime-e)}}var S=!1,C=-1,ee=5,w=-1;function T(){return g?!0:!(e.unstable_now()-w<ee)}function E(){if(g=!1,S){var t=e.unstable_now();w=t;var i=!0;try{a:{m=!1,h&&(h=!1,v(C),C=-1),p=!0;var a=f;try{b:{for(b(t),d=n(c);d!==null&&!(d.expirationTime>t&&T());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&A(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?D():S=!1}}}var D;if(typeof y==`function`)D=function(){y(E)};else if(typeof MessageChannel<`u`){var O=new MessageChannel,k=O.port2;O.port1.onmessage=E,D=function(){k.postMessage(null)}}else D=function(){_(E,0)};function A(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125<e?console.error(`forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported`):ee=0<e?Math.floor(1e3/e):5},e.unstable_getCurrentPriorityLevel=function(){return f},e.unstable_next=function(e){switch(f){case 1:case 2:case 3:var t=3;break;default:t=f}var n=f;f=t;try{return e()}finally{f=n}},e.unstable_requestPaint=function(){g=!0},e.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=f;f=e;try{return t()}finally{f=n}},e.unstable_scheduleCallback=function(r,i,a){var o=e.unstable_now();switch(typeof a==`object`&&a?(a=a.delay,a=typeof a==`number`&&0<a?o+a:o):a=o,r){case 1:var s=-1;break;case 2:s=250;break;case 5:s=1073741823;break;case 4:s=1e4;break;default:s=5e3}return s=a+s,r={id:u++,callback:i,priorityLevel:r,startTime:a,expirationTime:s,sortIndex:-1},a>o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,A(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,D()))),r},e.unstable_shouldYield=T,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),r=e(((e,t)=>{t.exports=n()})),i=e((e=>{var n=t();function r(e){var t=`https://react.dev/errors/`+e;if(1<arguments.length){t+=`?args[]=`+encodeURIComponent(arguments[1]);for(var n=2;n<arguments.length;n++)t+=`&args[]=`+encodeURIComponent(arguments[n])}return`Minified React error #`+e+`; visit `+t+` for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`}function i(){}var a={d:{f:i,r:function(){throw Error(r(522))},D:i,C:i,L:i,m:i,X:i,S:i,M:i},p:0,findDOMNode:null},o=Symbol.for(`react.portal`);function s(e,t,n){var r=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:o,key:r==null?null:``+r,children:e,containerInfo:t,implementation:n}}var c=n.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;function l(e,t){if(e===`font`)return``;if(typeof t==`string`)return t===`use-credentials`?t:``}e.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=a,e.createPortal=function(e,t){var n=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;if(!t||t.nodeType!==1&&t.nodeType!==9&&t.nodeType!==11)throw Error(r(299));return s(e,t,null,n)},e.flushSync=function(e){var t=c.T,n=a.p;try{if(c.T=null,a.p=2,e)return e()}finally{c.T=t,a.p=n,a.d.f()}},e.preconnect=function(e,t){typeof e==`string`&&(t?(t=t.crossOrigin,t=typeof t==`string`?t===`use-credentials`?t:``:void 0):t=null,a.d.C(e,t))},e.prefetchDNS=function(e){typeof e==`string`&&a.d.D(e)},e.preinit=function(e,t){if(typeof e==`string`&&t&&typeof t.as==`string`){var n=t.as,r=l(n,t.crossOrigin),i=typeof t.integrity==`string`?t.integrity:void 0,o=typeof t.fetchPriority==`string`?t.fetchPriority:void 0;n===`style`?a.d.S(e,typeof t.precedence==`string`?t.precedence:void 0,{crossOrigin:r,integrity:i,fetchPriority:o}):n===`script`&&a.d.X(e,{crossOrigin:r,integrity:i,fetchPriority:o,nonce:typeof t.nonce==`string`?t.nonce:void 0})}},e.preinitModule=function(e,t){if(typeof e==`string`)if(typeof t==`object`&&t){if(t.as==null||t.as===`script`){var n=l(t.as,t.crossOrigin);a.d.M(e,{crossOrigin:n,integrity:typeof t.integrity==`string`?t.integrity:void 0,nonce:typeof t.nonce==`string`?t.nonce:void 0})}}else t??a.d.M(e)},e.preload=function(e,t){if(typeof e==`string`&&typeof t==`object`&&t&&typeof t.as==`string`){var n=t.as,r=l(n,t.crossOrigin);a.d.L(e,n,{crossOrigin:r,integrity:typeof t.integrity==`string`?t.integrity:void 0,nonce:typeof t.nonce==`string`?t.nonce:void 0,type:typeof t.type==`string`?t.type:void 0,fetchPriority:typeof t.fetchPriority==`string`?t.fetchPriority:void 0,referrerPolicy:typeof t.referrerPolicy==`string`?t.referrerPolicy:void 0,imageSrcSet:typeof t.imageSrcSet==`string`?t.imageSrcSet:void 0,imageSizes:typeof t.imageSizes==`string`?t.imageSizes:void 0,media:typeof t.media==`string`?t.media:void 0})}},e.preloadModule=function(e,t){if(typeof e==`string`)if(t){var n=l(t.as,t.crossOrigin);a.d.m(e,{as:typeof t.as==`string`&&t.as!==`script`?t.as:void 0,crossOrigin:n,integrity:typeof t.integrity==`string`?t.integrity:void 0})}else a.d.m(e)},e.requestFormReset=function(e){a.d.r(e)},e.unstable_batchedUpdates=function(e,t){return e(t)},e.useFormState=function(e,t,n){return c.H.useFormState(e,t,n)},e.useFormStatus=function(){return c.H.useHostTransitionStatus()},e.version=`19.2.5`})),a=e(((e,t)=>{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=i()})),o=e((e=>{var n=r(),i=t(),o=a();function s(e){var t=`https://react.dev/errors/`+e;if(1<arguments.length){t+=`?args[]=`+encodeURIComponent(arguments[1]);for(var n=2;n<arguments.length;n++)t+=`&args[]=`+encodeURIComponent(arguments[n])}return`Minified React error #`+e+`; visit `+t+` for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`}function c(e){return!(!e||e.nodeType!==1&&e.nodeType!==9&&e.nodeType!==11)}function l(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do t=e,t.flags&4098&&(n=t.return),e=t.return;while(e)}return t.tag===3?n:null}function u(e){if(e.tag===13){var t=e.memoizedState;if(t===null&&(e=e.alternate,e!==null&&(t=e.memoizedState)),t!==null)return t.dehydrated}return null}function d(e){if(e.tag===31){var t=e.memoizedState;if(t===null&&(e=e.alternate,e!==null&&(t=e.memoizedState)),t!==null)return t.dehydrated}return null}function f(e){if(l(e)!==e)throw Error(s(188))}function p(e){var t=e.alternate;if(!t){if(t=l(e),t===null)throw Error(s(188));return t===e?e:null}for(var n=e,r=t;;){var i=n.return;if(i===null)break;var a=i.alternate;if(a===null){if(r=i.return,r!==null){n=r;continue}break}if(i.child===a.child){for(a=i.child;a;){if(a===n)return f(i),e;if(a===r)return f(i),t;a=a.sibling}throw Error(s(188))}if(n.return!==r.return)n=i,r=a;else{for(var o=!1,c=i.child;c;){if(c===n){o=!0,n=i,r=a;break}if(c===r){o=!0,r=i,n=a;break}c=c.sibling}if(!o){for(c=a.child;c;){if(c===n){o=!0,n=a,r=i;break}if(c===r){o=!0,r=a,n=i;break}c=c.sibling}if(!o)throw Error(s(189))}}if(n.alternate!==r)throw Error(s(190))}if(n.tag!==3)throw Error(s(188));return n.stateNode.current===n?e:t}function m(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e;for(e=e.child;e!==null;){if(t=m(e),t!==null)return t;e=e.sibling}return null}var h=Object.assign,g=Symbol.for(`react.element`),_=Symbol.for(`react.transitional.element`),v=Symbol.for(`react.portal`),y=Symbol.for(`react.fragment`),b=Symbol.for(`react.strict_mode`),x=Symbol.for(`react.profiler`),S=Symbol.for(`react.consumer`),C=Symbol.for(`react.context`),ee=Symbol.for(`react.forward_ref`),w=Symbol.for(`react.suspense`),T=Symbol.for(`react.suspense_list`),E=Symbol.for(`react.memo`),D=Symbol.for(`react.lazy`),O=Symbol.for(`react.activity`),k=Symbol.for(`react.memo_cache_sentinel`),A=Symbol.iterator;function te(e){return typeof e!=`object`||!e?null:(e=A&&e[A]||e[`@@iterator`],typeof e==`function`?e:null)}var j=Symbol.for(`react.client.reference`);function M(e){if(e==null)return null;if(typeof e==`function`)return e.$$typeof===j?null:e.displayName||e.name||null;if(typeof e==`string`)return e;switch(e){case y:return`Fragment`;case x:return`Profiler`;case b:return`StrictMode`;case w:return`Suspense`;case T:return`SuspenseList`;case O:return`Activity`}if(typeof e==`object`)switch(e.$$typeof){case v:return`Portal`;case C:return e.displayName||`Context`;case S:return(e._context.displayName||`Context`)+`.Consumer`;case ee:var t=e.render;return e=e.displayName,e||=(e=t.displayName||t.name||``,e===``?`ForwardRef`:`ForwardRef(`+e+`)`),e;case E:return t=e.displayName||null,t===null?M(e.type)||`Memo`:t;case D:t=e._payload,e=e._init;try{return M(e(t))}catch{}}return null}var N=Array.isArray,P=i.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,F=o.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,ne={pending:!1,data:null,method:null,action:null},I=[],L=-1;function re(e){return{current:e}}function R(e){0>L||(e.current=I[L],I[L]=null,L--)}function z(e,t){L++,I[L]=e.current,e.current=t}var B=re(null),ie=re(null),ae=re(null),oe=re(null);function se(e,t){switch(z(ae,t),z(ie,e),z(B,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Vd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Vd(t),e=Hd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}R(B),z(B,e)}function ce(){R(B),R(ie),R(ae)}function V(e){e.memoizedState!==null&&z(oe,e);var t=B.current,n=Hd(t,e.type);t!==n&&(z(ie,e),z(B,n))}function le(e){ie.current===e&&(R(B),R(ie)),oe.current===e&&(R(oe),Qf._currentValue=ne)}var H,ue;function de(e){if(H===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);H=t&&t[1]||``,ue=-1<e.stack.indexOf(`
1
+ import{t as e}from"./rolldown-runtime-CkqCuyE9.js";import{nt as t}from"./icons-Bs7OG8yi.js";var n=e((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0<n;){var r=n-1>>>1,a=e[r];if(0<i(a,t))e[r]=t,e[n]=a,n=r;else break a}}function n(e){return e.length===0?null:e[0]}function r(e){if(e.length===0)return null;var t=e[0],n=e.pop();if(n!==t){e[0]=n;a:for(var r=0,a=e.length,o=a>>>1;r<o;){var s=2*(r+1)-1,c=e[s],l=s+1,u=e[l];if(0>i(c,n))l<a&&0>i(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(l<a&&0>i(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,D());else{var t=n(l);t!==null&&A(x,t.startTime-e)}}var S=!1,C=-1,ee=5,w=-1;function T(){return g?!0:!(e.unstable_now()-w<ee)}function E(){if(g=!1,S){var t=e.unstable_now();w=t;var i=!0;try{a:{m=!1,h&&(h=!1,v(C),C=-1),p=!0;var a=f;try{b:{for(b(t),d=n(c);d!==null&&!(d.expirationTime>t&&T());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&A(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?D():S=!1}}}var D;if(typeof y==`function`)D=function(){y(E)};else if(typeof MessageChannel<`u`){var O=new MessageChannel,k=O.port2;O.port1.onmessage=E,D=function(){k.postMessage(null)}}else D=function(){_(E,0)};function A(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125<e?console.error(`forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported`):ee=0<e?Math.floor(1e3/e):5},e.unstable_getCurrentPriorityLevel=function(){return f},e.unstable_next=function(e){switch(f){case 1:case 2:case 3:var t=3;break;default:t=f}var n=f;f=t;try{return e()}finally{f=n}},e.unstable_requestPaint=function(){g=!0},e.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=f;f=e;try{return t()}finally{f=n}},e.unstable_scheduleCallback=function(r,i,a){var o=e.unstable_now();switch(typeof a==`object`&&a?(a=a.delay,a=typeof a==`number`&&0<a?o+a:o):a=o,r){case 1:var s=-1;break;case 2:s=250;break;case 5:s=1073741823;break;case 4:s=1e4;break;default:s=5e3}return s=a+s,r={id:u++,callback:i,priorityLevel:r,startTime:a,expirationTime:s,sortIndex:-1},a>o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,A(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,D()))),r},e.unstable_shouldYield=T,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),r=e(((e,t)=>{t.exports=n()})),i=e((e=>{var n=t();function r(e){var t=`https://react.dev/errors/`+e;if(1<arguments.length){t+=`?args[]=`+encodeURIComponent(arguments[1]);for(var n=2;n<arguments.length;n++)t+=`&args[]=`+encodeURIComponent(arguments[n])}return`Minified React error #`+e+`; visit `+t+` for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`}function i(){}var a={d:{f:i,r:function(){throw Error(r(522))},D:i,C:i,L:i,m:i,X:i,S:i,M:i},p:0,findDOMNode:null},o=Symbol.for(`react.portal`);function s(e,t,n){var r=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:o,key:r==null?null:``+r,children:e,containerInfo:t,implementation:n}}var c=n.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;function l(e,t){if(e===`font`)return``;if(typeof t==`string`)return t===`use-credentials`?t:``}e.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=a,e.createPortal=function(e,t){var n=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;if(!t||t.nodeType!==1&&t.nodeType!==9&&t.nodeType!==11)throw Error(r(299));return s(e,t,null,n)},e.flushSync=function(e){var t=c.T,n=a.p;try{if(c.T=null,a.p=2,e)return e()}finally{c.T=t,a.p=n,a.d.f()}},e.preconnect=function(e,t){typeof e==`string`&&(t?(t=t.crossOrigin,t=typeof t==`string`?t===`use-credentials`?t:``:void 0):t=null,a.d.C(e,t))},e.prefetchDNS=function(e){typeof e==`string`&&a.d.D(e)},e.preinit=function(e,t){if(typeof e==`string`&&t&&typeof t.as==`string`){var n=t.as,r=l(n,t.crossOrigin),i=typeof t.integrity==`string`?t.integrity:void 0,o=typeof t.fetchPriority==`string`?t.fetchPriority:void 0;n===`style`?a.d.S(e,typeof t.precedence==`string`?t.precedence:void 0,{crossOrigin:r,integrity:i,fetchPriority:o}):n===`script`&&a.d.X(e,{crossOrigin:r,integrity:i,fetchPriority:o,nonce:typeof t.nonce==`string`?t.nonce:void 0})}},e.preinitModule=function(e,t){if(typeof e==`string`)if(typeof t==`object`&&t){if(t.as==null||t.as===`script`){var n=l(t.as,t.crossOrigin);a.d.M(e,{crossOrigin:n,integrity:typeof t.integrity==`string`?t.integrity:void 0,nonce:typeof t.nonce==`string`?t.nonce:void 0})}}else t??a.d.M(e)},e.preload=function(e,t){if(typeof e==`string`&&typeof t==`object`&&t&&typeof t.as==`string`){var n=t.as,r=l(n,t.crossOrigin);a.d.L(e,n,{crossOrigin:r,integrity:typeof t.integrity==`string`?t.integrity:void 0,nonce:typeof t.nonce==`string`?t.nonce:void 0,type:typeof t.type==`string`?t.type:void 0,fetchPriority:typeof t.fetchPriority==`string`?t.fetchPriority:void 0,referrerPolicy:typeof t.referrerPolicy==`string`?t.referrerPolicy:void 0,imageSrcSet:typeof t.imageSrcSet==`string`?t.imageSrcSet:void 0,imageSizes:typeof t.imageSizes==`string`?t.imageSizes:void 0,media:typeof t.media==`string`?t.media:void 0})}},e.preloadModule=function(e,t){if(typeof e==`string`)if(t){var n=l(t.as,t.crossOrigin);a.d.m(e,{as:typeof t.as==`string`&&t.as!==`script`?t.as:void 0,crossOrigin:n,integrity:typeof t.integrity==`string`?t.integrity:void 0})}else a.d.m(e)},e.requestFormReset=function(e){a.d.r(e)},e.unstable_batchedUpdates=function(e,t){return e(t)},e.useFormState=function(e,t,n){return c.H.useFormState(e,t,n)},e.useFormStatus=function(){return c.H.useHostTransitionStatus()},e.version=`19.2.5`})),a=e(((e,t)=>{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=i()})),o=e((e=>{var n=r(),i=t(),o=a();function s(e){var t=`https://react.dev/errors/`+e;if(1<arguments.length){t+=`?args[]=`+encodeURIComponent(arguments[1]);for(var n=2;n<arguments.length;n++)t+=`&args[]=`+encodeURIComponent(arguments[n])}return`Minified React error #`+e+`; visit `+t+` for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`}function c(e){return!(!e||e.nodeType!==1&&e.nodeType!==9&&e.nodeType!==11)}function l(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do t=e,t.flags&4098&&(n=t.return),e=t.return;while(e)}return t.tag===3?n:null}function u(e){if(e.tag===13){var t=e.memoizedState;if(t===null&&(e=e.alternate,e!==null&&(t=e.memoizedState)),t!==null)return t.dehydrated}return null}function d(e){if(e.tag===31){var t=e.memoizedState;if(t===null&&(e=e.alternate,e!==null&&(t=e.memoizedState)),t!==null)return t.dehydrated}return null}function f(e){if(l(e)!==e)throw Error(s(188))}function p(e){var t=e.alternate;if(!t){if(t=l(e),t===null)throw Error(s(188));return t===e?e:null}for(var n=e,r=t;;){var i=n.return;if(i===null)break;var a=i.alternate;if(a===null){if(r=i.return,r!==null){n=r;continue}break}if(i.child===a.child){for(a=i.child;a;){if(a===n)return f(i),e;if(a===r)return f(i),t;a=a.sibling}throw Error(s(188))}if(n.return!==r.return)n=i,r=a;else{for(var o=!1,c=i.child;c;){if(c===n){o=!0,n=i,r=a;break}if(c===r){o=!0,r=i,n=a;break}c=c.sibling}if(!o){for(c=a.child;c;){if(c===n){o=!0,n=a,r=i;break}if(c===r){o=!0,r=a,n=i;break}c=c.sibling}if(!o)throw Error(s(189))}}if(n.alternate!==r)throw Error(s(190))}if(n.tag!==3)throw Error(s(188));return n.stateNode.current===n?e:t}function m(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e;for(e=e.child;e!==null;){if(t=m(e),t!==null)return t;e=e.sibling}return null}var h=Object.assign,g=Symbol.for(`react.element`),_=Symbol.for(`react.transitional.element`),v=Symbol.for(`react.portal`),y=Symbol.for(`react.fragment`),b=Symbol.for(`react.strict_mode`),x=Symbol.for(`react.profiler`),S=Symbol.for(`react.consumer`),C=Symbol.for(`react.context`),ee=Symbol.for(`react.forward_ref`),w=Symbol.for(`react.suspense`),T=Symbol.for(`react.suspense_list`),E=Symbol.for(`react.memo`),D=Symbol.for(`react.lazy`),O=Symbol.for(`react.activity`),k=Symbol.for(`react.memo_cache_sentinel`),A=Symbol.iterator;function te(e){return typeof e!=`object`||!e?null:(e=A&&e[A]||e[`@@iterator`],typeof e==`function`?e:null)}var j=Symbol.for(`react.client.reference`);function M(e){if(e==null)return null;if(typeof e==`function`)return e.$$typeof===j?null:e.displayName||e.name||null;if(typeof e==`string`)return e;switch(e){case y:return`Fragment`;case x:return`Profiler`;case b:return`StrictMode`;case w:return`Suspense`;case T:return`SuspenseList`;case O:return`Activity`}if(typeof e==`object`)switch(e.$$typeof){case v:return`Portal`;case C:return e.displayName||`Context`;case S:return(e._context.displayName||`Context`)+`.Consumer`;case ee:var t=e.render;return e=e.displayName,e||=(e=t.displayName||t.name||``,e===``?`ForwardRef`:`ForwardRef(`+e+`)`),e;case E:return t=e.displayName||null,t===null?M(e.type)||`Memo`:t;case D:t=e._payload,e=e._init;try{return M(e(t))}catch{}}return null}var N=Array.isArray,P=i.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,F=o.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,ne={pending:!1,data:null,method:null,action:null},I=[],L=-1;function re(e){return{current:e}}function R(e){0>L||(e.current=I[L],I[L]=null,L--)}function z(e,t){L++,I[L]=e.current,e.current=t}var B=re(null),ie=re(null),ae=re(null),oe=re(null);function se(e,t){switch(z(ae,t),z(ie,e),z(B,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Vd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Vd(t),e=Hd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}R(B),z(B,e)}function ce(){R(B),R(ie),R(ae)}function V(e){e.memoizedState!==null&&z(oe,e);var t=B.current,n=Hd(t,e.type);t!==n&&(z(ie,e),z(B,n))}function le(e){ie.current===e&&(R(B),R(ie)),oe.current===e&&(R(oe),Qf._currentValue=ne)}var H,ue;function de(e){if(H===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);H=t&&t[1]||``,ue=-1<e.stack.indexOf(`
2
2
  at`)?` (<anonymous>)`:-1<e.stack.indexOf(`@`)?`@unknown:0:0`:``}return`
3
3
  `+H+e+ue}var fe=!1;function pe(e,t){if(!e||fe)return``;fe=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var n=function(){throw Error()};if(Object.defineProperty(n.prototype,`props`,{set:function(){throw Error()}}),typeof Reflect==`object`&&Reflect.construct){try{Reflect.construct(n,[])}catch(e){var r=e}Reflect.construct(e,[],n)}else{try{n.call()}catch(e){r=e}e.call(n.prototype)}}else{try{throw Error()}catch(e){r=e}(n=e())&&typeof n.catch==`function`&&n.catch(function(){})}}catch(e){if(e&&r&&typeof e.stack==`string`)return[e.stack,r.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName=`DetermineComponentFrameRoot`;var i=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,`name`);i&&i.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,`name`,{value:`DetermineComponentFrameRoot`});var a=r.DetermineComponentFrameRoot(),o=a[0],s=a[1];if(o&&s){var c=o.split(`
4
4
  `),l=s.split(`
@@ -0,0 +1 @@
1
+ function e(e){return e.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,``)}export{e as t};
@@ -0,0 +1 @@
1
+ function e(e,t,n){return{temperature:t?.temperature,maxTokens:t?.maxTokens,signal:t?.signal,apiKey:n||t?.apiKey,transport:t?.transport,cacheRetention:t?.cacheRetention,sessionId:t?.sessionId,headers:t?.headers,onPayload:t?.onPayload,onResponse:t?.onResponse,timeoutMs:t?.timeoutMs,maxRetries:t?.maxRetries,maxRetryDelayMs:t?.maxRetryDelayMs,metadata:t?.metadata}}function t(e){return e===`xhigh`?`high`:e}function n(e,n,r,i){let a={minimal:1024,low:2048,medium:8192,high:16384,...i}[t(r)],o=e===void 0?n:Math.min(e+a,n);return o<=a&&(a=Math.max(0,o-1024)),{maxTokens:o,thinkingBudget:a}}var r=`(image omitted: model does not support images)`,i=`(tool image omitted: model does not support images)`;function a(e,t){let n=[],r=!1;for(let i of e){if(i.type===`image`){r||n.push({type:`text`,text:t}),r=!0;continue}n.push(i),r=i.text===t}return n}function o(e,t){return t.input.includes(`image`)?e:e.map(e=>e.role===`user`&&Array.isArray(e.content)?{...e,content:a(e.content,r)}:e.role===`toolResult`?{...e,content:a(e.content,i)}:e)}function s(e,t,n){let r=new Map,i=o(e,t).map(e=>{if(e.role===`user`)return e;if(e.role===`toolResult`){let t=r.get(e.toolCallId);return t&&t!==e.toolCallId?{...e,toolCallId:t}:e}if(e.role===`assistant`){let i=e,a=i.provider===t.provider&&i.api===t.api&&i.model===t.id,o=i.content.flatMap(e=>{if(e.type===`thinking`)return e.redacted?a?e:[]:a&&e.thinkingSignature?e:!e.thinking||e.thinking.trim()===``?[]:a?e:{type:`text`,text:e.thinking};if(e.type===`text`)return a?e:{type:`text`,text:e.text};if(e.type===`toolCall`){let o=e,s=o;if(!a&&o.thoughtSignature&&(s={...o},delete s.thoughtSignature),!a&&n){let e=n(o.id,t,i);e!==o.id&&(r.set(o.id,e),s={...s,id:e})}return s}return e});return{...i,content:o}}return e}),a=[],s=[],c=new Set,l=()=>{if(s.length>0){for(let e of s)c.has(e.id)||a.push({role:`toolResult`,toolCallId:e.id,toolName:e.name,content:[{type:`text`,text:`No result provided`}],isError:!0,timestamp:Date.now()});s=[],c=new Set}};for(let e=0;e<i.length;e++){let t=i[e];if(t.role===`assistant`){l();let e=t;if(e.stopReason===`error`||e.stopReason===`aborted`)continue;let n=e.content.filter(e=>e.type===`toolCall`);n.length>0&&(s=n,c=new Set),a.push(t)}else t.role===`toolResult`?(c.add(t.toolCallId),a.push(t)):(t.role===`user`&&l(),a.push(t))}return l(),a}export{n,e as r,s as t};
package/dist/index.html CHANGED
@@ -11,13 +11,13 @@
11
11
  <meta name="apple-mobile-web-app-title" content="QuickForge" />
12
12
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
13
13
  <title>速构 QuickForge</title>
14
- <script type="module" crossorigin src="/assets/index-s72bxhrh.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-C3bc5C3k.js"></script>
15
15
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-CkqCuyE9.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/lit-vendor-Dr3cpBGF.js">
17
17
  <link rel="modulepreload" crossorigin href="/assets/css-utils-rkE68RDy.js">
18
- <link rel="modulepreload" crossorigin href="/assets/icons-DmRYmmql.js">
19
- <link rel="modulepreload" crossorigin href="/assets/react-vendor-BsV2HYbc.js">
20
- <link rel="stylesheet" crossorigin href="/assets/index-C4m48ndP.css">
18
+ <link rel="modulepreload" crossorigin href="/assets/icons-Bs7OG8yi.js">
19
+ <link rel="modulepreload" crossorigin href="/assets/react-vendor-Cu-7p9CI.js">
20
+ <link rel="stylesheet" crossorigin href="/assets/index-C7oT9Rdw.css">
21
21
  </head>
22
22
  <body>
23
23
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shawnstack/quickforge",
3
- "version": "1.3.24",
3
+ "version": "1.3.25",
4
4
  "description": "AI chat application with YOLO-mode local workspace tools. React + Vite + Tailwind CSS frontend, local Node.js storage server.",
5
5
  "keywords": [
6
6
  "ai",
@@ -45,8 +45,8 @@
45
45
  "@dnd-kit/core": "^6.3.1",
46
46
  "@dnd-kit/sortable": "^10.0.0",
47
47
  "@dnd-kit/utilities": "^3.2.2",
48
- "@mariozechner/pi-agent-core": "^0.73.1",
49
- "@mariozechner/pi-ai": "^0.73.1",
48
+ "@earendil-works/pi-agent-core": "^0.75.3",
49
+ "@earendil-works/pi-ai": "^0.75.3",
50
50
  "@modelcontextprotocol/sdk": "^1.29.0",
51
51
  "ws": "^8.20.1"
52
52
  },
@@ -1,17 +1,17 @@
1
1
  import { EventEmitter } from 'node:events'
2
2
  import { randomUUID } from 'node:crypto'
3
- import { Agent } from '@mariozechner/pi-agent-core'
3
+ import { Agent } from '@earendil-works/pi-agent-core'
4
4
  import { streamSimpleWithAiHttpLogging } from './ai-http-logger.mjs'
5
- import { toolHandlers, loadSkillToolContext, abortRunningCommand } from './tools/index.mjs'
5
+ import { loadSkillToolContext, abortRunningCommand } from './tools/index.mjs'
6
6
  import { createSkillTools, workspaceTools } from './tools/definitions.mjs'
7
- import { callMcpTool, createMcpToolDefinitions, isMcpToolName } from './mcp/registry.mjs'
7
+ import { createMcpToolDefinitions, isMcpToolName } from './mcp/registry.mjs'
8
8
  import {
9
9
  composeSubagentSystemPrompt,
10
10
  formatSubagentTask,
11
11
  } from './subagents.mjs'
12
12
  import { agentProfileSnapshot, getAgentProfile } from './agent-profiles.mjs'
13
13
  import { projectContextFromId, readProjectConfig } from './project-config.mjs'
14
- import { readStore, atomicUpdate, readSessionValue, writeSessionValue, deleteSessionValue } from './storage.mjs'
14
+ import { readStore, atomicUpdate, atomicSessionMetadataUpdate, readSessionValue, writeSessionValue, deleteSessionValue } from './storage.mjs'
15
15
  import { logger } from './utils/logger.mjs'
16
16
  import { buildSystemPrompt, generateAiTitle, generateTitle } from './session-utils.mjs'
17
17
  import { restoreReasoningContentInPayload } from './reasoning-cache.mjs'
@@ -30,70 +30,22 @@ import {
30
30
  parseInternalCommandInvocation,
31
31
  resolveCustomCommandInvocation,
32
32
  } from './custom-commands.mjs'
33
+ import { omitDetailsForLlm, serverConvertToLlm, messageText, lastAssistantText } from './message-converters.mjs'
34
+ import { isPlainObject, mergeQuickForgeTiming, wrapToolDefinition, wrapMcpToolDefinition, sessionSkillsContext } from './tool-wiring.mjs'
35
+ import {
36
+ APPROVAL_TIMEOUT_MS,
37
+ commandRestrictedTools,
38
+ safeReadTools,
39
+ pendingApprovals,
40
+ pendingAutoCompactApprovals,
41
+ commandToolPermissionError,
42
+ createCommandToolPermissions,
43
+ } from './approval-store.mjs'
33
44
 
34
45
  // ---------------------------------------------------------------------------
35
46
  // Tool definitions (server-side, no REST roundtrip)
36
47
  // ---------------------------------------------------------------------------
37
48
 
38
- function isPlainObject(value) {
39
- return Boolean(value && typeof value === 'object' && !Array.isArray(value))
40
- }
41
-
42
- function mergeQuickForgeTiming(details, timing) {
43
- if (!isPlainObject(details)) return { quickforgeTiming: timing }
44
- return { ...details, quickforgeTiming: timing }
45
- }
46
-
47
- function wrapToolDefinition(definition, context, toolPermissions) {
48
- const handler = toolHandlers[definition.name]
49
- if (!handler) throw new Error(`Missing handler for tool: ${definition.name}`)
50
- return {
51
- ...definition,
52
- execute: async (_toolCallId, params, signal, onUpdate) => {
53
- if (toolPermissions) {
54
- const permissionError = toolPermissions(definition.name)
55
- if (permissionError) throw new Error(permissionError)
56
- }
57
-
58
- const startedAt = Date.now()
59
- const startedAtPerf = performance.now()
60
- const result = await handler(params || {}, context, { signal, onUpdate, toolCallId: _toolCallId })
61
- const finishedAt = Date.now()
62
- const durationMs = Math.max(0, Math.round(performance.now() - startedAtPerf))
63
- const details = mergeQuickForgeTiming(result.details, { startedAt, finishedAt, durationMs })
64
- return {
65
- content: [{ type: 'text', text: result.content }],
66
- details: isPlainObject(details) ? { ...details, toolCallId: _toolCallId } : details,
67
- }
68
- },
69
- }
70
- }
71
-
72
- function wrapMcpToolDefinition(definition, toolPermissions) {
73
- return {
74
- ...definition,
75
- execute: async (_toolCallId, params) => {
76
- if (toolPermissions) {
77
- const permissionError = toolPermissions(definition.name)
78
- if (permissionError) throw new Error(permissionError)
79
- }
80
-
81
- const startedAt = Date.now()
82
- const startedAtPerf = performance.now()
83
- const result = await callMcpTool(definition.name, params || {})
84
- const finishedAt = Date.now()
85
- const durationMs = Math.max(0, Math.round(performance.now() - startedAtPerf))
86
- if (result.isError) {
87
- throw new Error(result.content || `MCP tool failed: ${definition.name}`)
88
- }
89
- return {
90
- content: [{ type: 'text', text: result.content }],
91
- details: mergeQuickForgeTiming(result.details, { startedAt, finishedAt, durationMs }),
92
- }
93
- },
94
- }
95
- }
96
-
97
49
  function wrapSubagentToolDefinition(definition, parentSessionId) {
98
50
  return {
99
51
  ...definition,
@@ -154,13 +106,6 @@ async function createServerTools(projectId, projectContext, skillsContext, inclu
154
106
  return tools
155
107
  }
156
108
 
157
- function sessionSkillsContext(session) {
158
- return {
159
- globalSkillNames: session.globalSkillNames,
160
- projectSkillNames: session.projectSkillNames,
161
- }
162
- }
163
-
164
109
  async function rebuildSessionTools(session) {
165
110
  session.agent.state.tools = await createServerTools(
166
111
  session.projectId,
@@ -181,31 +126,8 @@ const agentSessions = new Map()
181
126
  /** @typedef {{ agent: Agent, projectContext: object|null, projectId: string|null, yoloMode: boolean, model: object, thinkingLevel: string, scope: string, title: string, createdAt: string, status: string, startedAt: string|null, finishedAt: string|null, listeners: Set<function>, idleTimer: NodeJS.Timeout|null, eventBus: EventEmitter }} AgentSession */
182
127
 
183
128
  const IDLE_TIMEOUT_MS = 30 * 60 * 1000 // 30 minutes
184
- const APPROVAL_TIMEOUT_MS = 5 * 60 * 1000 // 5 minutes for tool approval
185
129
  const SUBAGENT_DEFAULT_TIMEOUT_MS = 30 * 60 * 1000
186
- const commandRestrictedTools = new Set(['write_file', 'edit_file', 'run_command', 'run_subagent'])
187
- const safeReadTools = new Set(['read_file', 'grep_files'])
188
- const pendingApprovals = new Map() // toolCallId → { resolve, reject, sessionId, toolName, args, source, timeout }
189
- const pendingAutoCompactApprovals = new Map() // approvalId → { resolve, reject, sessionId, timeout }
190
-
191
- function commandToolPermissionError(session, toolName) {
192
- const permissions = session?.activeCommandPermissions
193
- if (!permissions || !commandRestrictedTools.has(toolName)) return null
194
- if (toolName === 'run_command' && permissions.allowCommands === false) {
195
- return `Command /${session.activeCommandName} does not allow running shell commands.`
196
- }
197
- if (toolName === 'run_subagent' && permissions.allowCommands === false) {
198
- return `Command /${session.activeCommandName} does not allow running subagents.`
199
- }
200
- if ((toolName === 'write_file' || toolName === 'edit_file') && permissions.allowEdit === false) {
201
- return `Command /${session.activeCommandName} does not allow editing files.`
202
- }
203
- return null
204
- }
205
-
206
- function createCommandToolPermissions(session) {
207
- return (toolName) => commandToolPermissionError(session, toolName)
208
- }
130
+ const SUBAGENT_TRACE_THROTTLE_MS = 150
209
131
 
210
132
  /**
211
133
  * Create a Promise that only resolves when the user accepts or rejects the tool call.
@@ -224,8 +146,14 @@ function createApprovalPromise(session, toolCallId, toolName, args, source) {
224
146
  resolve({ block: true, reason: `Approval timeout for ${toolName}` })
225
147
  }, APPROVAL_TIMEOUT_MS)
226
148
 
149
+ let onAbort = null
150
+
227
151
  const cleanup = () => {
228
152
  clearTimeout(timeout)
153
+ if (onAbort) {
154
+ session.agent.signal?.removeEventListener('abort', onAbort)
155
+ onAbort = null
156
+ }
229
157
  if (settled) return
230
158
  settled = true
231
159
  pendingApprovals.delete(toolCallId)
@@ -239,7 +167,7 @@ function createApprovalPromise(session, toolCallId, toolName, args, source) {
239
167
  reject(new Error('Run aborted'))
240
168
  return
241
169
  }
242
- const onAbort = () => {
170
+ onAbort = () => {
243
171
  cleanup()
244
172
  reject(new Error('Run aborted'))
245
173
  }
@@ -289,8 +217,14 @@ function createAutoCompactApprovalPromise(session, details = {}) {
289
217
  resolve(false)
290
218
  }, APPROVAL_TIMEOUT_MS)
291
219
 
220
+ let onAbort = null
221
+
292
222
  const cleanup = () => {
293
223
  clearTimeout(timeout)
224
+ if (onAbort) {
225
+ session.agent.signal?.removeEventListener('abort', onAbort)
226
+ onAbort = null
227
+ }
294
228
  if (settled) return
295
229
  settled = true
296
230
  pendingAutoCompactApprovals.delete(approvalId)
@@ -303,7 +237,7 @@ function createAutoCompactApprovalPromise(session, details = {}) {
303
237
  reject(new Error('Run aborted'))
304
238
  return
305
239
  }
306
- const onAbort = () => {
240
+ onAbort = () => {
307
241
  cleanup()
308
242
  reject(new Error('Run aborted'))
309
243
  }
@@ -665,67 +599,6 @@ ${taskText}
665
599
  </plan_command_invocation>`
666
600
  }
667
601
 
668
- function omitDetailsForLlm(message) {
669
- if (!message || typeof message !== 'object' || message.details === undefined) return message
670
- const copy = { ...message }
671
- delete copy.details
672
- return copy
673
- }
674
-
675
- /**
676
- * Convert AgentMessage[] to LLM-compatible Message[].
677
- * Handles "user-with-attachments" → "user" with multi-modal content blocks.
678
- * Without this the default pi-agent-core convertToLlm silently drops
679
- * user-with-attachments messages, so the LLM never sees attachments.
680
- */
681
- function serverConvertToLlm(messages) {
682
- return messages
683
- .filter(m => m.role !== 'artifact')
684
- .map(m => {
685
- if (m.role === 'user-with-attachments') {
686
- const textContent = typeof m.content === 'string'
687
- ? [{ type: 'text', text: m.content }]
688
- : [...m.content]
689
- if (Array.isArray(m.attachments)) {
690
- for (const att of m.attachments) {
691
- if (att.type === 'image' && att.content) {
692
- textContent.push({ type: 'image', data: att.content, mimeType: att.mimeType })
693
- } else if (att.type === 'document' && att.extractedText) {
694
- textContent.push({ type: 'text', text: `\n\n[Document: ${att.fileName}]\n${att.extractedText}` })
695
- }
696
- }
697
- }
698
- return omitDetailsForLlm({ ...m, role: 'user', content: textContent })
699
- }
700
- if (m.role === 'user' || m.role === 'assistant' || m.role === 'toolResult') return omitDetailsForLlm(m)
701
- return null
702
- })
703
- .filter(Boolean)
704
- }
705
-
706
- function messageText(message) {
707
- const content = message?.content
708
- if (typeof content === 'string') return content
709
- if (Array.isArray(content)) {
710
- return content
711
- .filter((block) => block?.type === 'text')
712
- .map((block) => block.text ?? '')
713
- .join('\n')
714
- .trim()
715
- }
716
- return ''
717
- }
718
-
719
- function lastAssistantText(messages) {
720
- for (let index = messages.length - 1; index >= 0; index--) {
721
- const message = messages[index]
722
- if (message?.role !== 'assistant') continue
723
- const text = messageText(message)
724
- if (text) return text
725
- }
726
- return ''
727
- }
728
-
729
602
  async function runSubagent(parentSession, params, parentSignal, onUpdate) {
730
603
  const profile = await getAgentProfile(params?.subagent)
731
604
  if (!profile || !profile.enabledAsSubagent) {
@@ -755,6 +628,9 @@ async function runSubagent(parentSession, params, parentSignal, onUpdate) {
755
628
  let latestMessages = []
756
629
  let latestPendingToolCalls = []
757
630
  let toolsForClient = []
631
+ let lastTraceAt = 0
632
+ let tracePending = false
633
+ let traceTimer = null
758
634
 
759
635
  const tools = await createServerTools(
760
636
  parentSession.projectId,
@@ -774,6 +650,12 @@ async function runSubagent(parentSession, params, parentSignal, onUpdate) {
774
650
  toolsForClient = tools.map(({ execute, prepareArguments, ...tool }) => tool)
775
651
 
776
652
  const emitSubagentTrace = () => {
653
+ if (traceTimer) {
654
+ clearTimeout(traceTimer)
655
+ traceTimer = null
656
+ }
657
+ tracePending = false
658
+ lastTraceAt = Date.now()
777
659
  onUpdate?.({
778
660
  content: [],
779
661
  details: {
@@ -792,6 +674,19 @@ async function runSubagent(parentSession, params, parentSignal, onUpdate) {
792
674
  })
793
675
  }
794
676
 
677
+ const emitSubagentTraceThrottled = () => {
678
+ const elapsed = Date.now() - lastTraceAt
679
+ if (elapsed >= SUBAGENT_TRACE_THROTTLE_MS) {
680
+ emitSubagentTrace()
681
+ return
682
+ }
683
+ tracePending = true
684
+ if (traceTimer) return
685
+ traceTimer = setTimeout(() => {
686
+ if (tracePending) emitSubagentTrace()
687
+ }, SUBAGENT_TRACE_THROTTLE_MS - elapsed)
688
+ }
689
+
795
690
  const systemPrompt = composeSubagentSystemPrompt({
796
691
  definition,
797
692
  parentSystemPrompt: parentSession.agent.state.systemPrompt,
@@ -848,7 +743,11 @@ async function runSubagent(parentSession, params, parentSignal, onUpdate) {
848
743
  latestMessages = [...latestMessages, event.message]
849
744
  }
850
745
  }
851
- emitSubagentTrace()
746
+ if (event.type === 'tool_execution_start' || event.type === 'tool_execution_end' || event.type === 'message_end') {
747
+ emitSubagentTrace()
748
+ } else {
749
+ emitSubagentTraceThrottled()
750
+ }
852
751
  })
853
752
 
854
753
  let timedOut = false
@@ -866,6 +765,7 @@ async function runSubagent(parentSession, params, parentSignal, onUpdate) {
866
765
  } finally {
867
766
  clearTimeout(timeout)
868
767
  parentSignal?.removeEventListener?.('abort', onParentAbort)
768
+ emitSubagentTrace()
869
769
  }
870
770
 
871
771
  const content = lastAssistantText(subagent.state.messages) || `Subagent ${definition.name} completed without a text response.`
@@ -1181,6 +1081,7 @@ export async function createAgent(sessionId, config = {}) {
1181
1081
  if (event.type === 'agent_end') {
1182
1082
  session.status = session.agent.state.errorMessage ? 'error' : 'idle'
1183
1083
  session.finishedAt = new Date().toISOString()
1084
+ session.toolTimings?.clear()
1184
1085
  resetIdleTimer(session)
1185
1086
 
1186
1087
  // Persist after run ends
@@ -1237,7 +1138,7 @@ async function persistSession(session) {
1237
1138
  if (messages.length === 0) {
1238
1139
  try {
1239
1140
  await deleteSessionValue(sessionId)
1240
- await atomicUpdate('sessions-metadata', (data) => {
1141
+ await atomicSessionMetadataUpdate(scope, projectId, (data) => {
1241
1142
  delete data[sessionId]
1242
1143
  return data
1243
1144
  })
@@ -1324,7 +1225,7 @@ async function persistSession(session) {
1324
1225
  // Write to storage atomically (read-modify-write within queue)
1325
1226
  try {
1326
1227
  await writeSessionValue(sessionId, sessionData)
1327
- await atomicUpdate('sessions-metadata', (data) => {
1228
+ await atomicSessionMetadataUpdate(scope, projectId, (data) => {
1328
1229
  data[sessionId] = {
1329
1230
  ...metadata,
1330
1231
  pinnedAt: data[sessionId]?.pinnedAt,
@@ -1426,6 +1327,10 @@ export async function runPrompt(sessionId, message) {
1426
1327
  throw Object.assign(new Error('Session not found'), { statusCode: 404 })
1427
1328
  }
1428
1329
 
1330
+ if (session.agent.state.isStreaming) {
1331
+ throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes.'), { statusCode: 409 })
1332
+ }
1333
+
1429
1334
  resetIdleTimer(session)
1430
1335
 
1431
1336
  // Build user message
@@ -1701,6 +1606,7 @@ export async function destroyAgent(sessionId) {
1701
1606
  logger.info(`Destroying session ${sessionId} (status: ${session.status})`, { sessionId, status: session.status })
1702
1607
 
1703
1608
  if (session.idleTimer) clearTimeout(session.idleTimer)
1609
+ session.toolTimings?.clear()
1704
1610
 
1705
1611
  try {
1706
1612
  session.agent.abort()
@@ -2,7 +2,7 @@ import fs from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { AsyncLocalStorage } from 'node:async_hooks'
4
4
  import { randomUUID } from 'node:crypto'
5
- import { streamSimple } from '@mariozechner/pi-ai'
5
+ import { streamSimple } from '@earendil-works/pi-ai'
6
6
  import { logsDir } from './storage.mjs'
7
7
 
8
8
  const PATCH_MARKER = Symbol.for('quickforge.aiHttpLogger.fetchPatched')
@@ -16,16 +16,31 @@ function currentLogFile() {
16
16
  return path.join(logsDir, `ai-http-${date}.jsonl`)
17
17
  }
18
18
 
19
- function writeAiHttpRecord(record) {
20
- if (!aiHttpLogEnabled) return
19
+ let logsDirEnsured = false
20
+
21
+ async function ensureLogsDir() {
22
+ if (logsDirEnsured) return
21
23
  try {
22
- fs.mkdirSync(logsDir, { recursive: true })
23
- fs.appendFile(currentLogFile(), `${JSON.stringify({ ts: new Date().toISOString(), ...record })}\n`, () => {})
24
+ const { promises: fsp } = await import('node:fs')
25
+ await fsp.mkdir(logsDir, { recursive: true })
26
+ logsDirEnsured = true
24
27
  } catch {
25
28
  // Keep AI calls working even when diagnostic logging fails.
26
29
  }
27
30
  }
28
31
 
32
+ function writeAiHttpRecord(record) {
33
+ if (!aiHttpLogEnabled) return
34
+ // Schedule async write — never blocks the event loop
35
+ void ensureLogsDir().then(() => {
36
+ try {
37
+ fs.appendFile(currentLogFile(), `${JSON.stringify({ ts: new Date().toISOString(), ...record })}\n`, () => {})
38
+ } catch {
39
+ // Keep AI calls working even when diagnostic logging fails.
40
+ }
41
+ })
42
+ }
43
+
29
44
  function headersToRecord(headers) {
30
45
  const result = {}
31
46
  if (!headers) return result
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Tool approval store — shared state and permission helpers.
3
+ *
4
+ * Manages the pending approval queues and command-tool permission checks.
5
+ * The Promise-based approval functions (createApprovalPromise,
6
+ * createAutoCompactApprovalPromise) remain in agent-manager.mjs because
7
+ * they depend on the agent event buses.
8
+ */
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Constants
12
+ // ---------------------------------------------------------------------------
13
+
14
+ export const APPROVAL_TIMEOUT_MS = 5 * 60 * 1000 // 5 minutes for tool approval
15
+
16
+ // ---------------------------------------------------------------------------
17
+ // Tool categories
18
+ // ---------------------------------------------------------------------------
19
+
20
+ export const commandRestrictedTools = new Set([
21
+ 'write_file',
22
+ 'edit_file',
23
+ 'run_command',
24
+ 'run_subagent',
25
+ ])
26
+
27
+ export const safeReadTools = new Set([
28
+ 'read_file',
29
+ 'grep_files',
30
+ ])
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Pending approval queues
34
+ // ---------------------------------------------------------------------------
35
+
36
+ /** toolCallId → { resolve, reject, sessionId, toolName, args, source, timeout } */
37
+ export const pendingApprovals = new Map()
38
+
39
+ /** approvalId → { resolve, reject, sessionId, timeout } */
40
+ export const pendingAutoCompactApprovals = new Map()
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Permission helpers
44
+ // ---------------------------------------------------------------------------
45
+
46
+ export function commandToolPermissionError(session, toolName) {
47
+ const permissions = session?.activeCommandPermissions
48
+ if (!permissions || !commandRestrictedTools.has(toolName)) return null
49
+ if (toolName === 'run_command' && permissions.allowCommands === false) {
50
+ return `Command /${session.activeCommandName} does not allow running shell commands.`
51
+ }
52
+ if (toolName === 'run_subagent' && permissions.allowCommands === false) {
53
+ return `Command /${session.activeCommandName} does not allow running subagents.`
54
+ }
55
+ if ((toolName === 'write_file' || toolName === 'edit_file') && permissions.allowEdit === false) {
56
+ return `Command /${session.activeCommandName} does not allow editing files.`
57
+ }
58
+ return null
59
+ }
60
+
61
+ export function createCommandToolPermissions(session) {
62
+ return (toolName) => commandToolPermissionError(session, toolName)
63
+ }