@shawnstack/quickforge 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +10 -10
  2. package/dist/assets/AgentProfilesPage-DKyIh3dE.js +1 -0
  3. package/dist/assets/ChatPanelHost-BUZ6scv9.js +242 -0
  4. package/dist/assets/{PluginsPage-kiBq0gOT.js → PluginsPage-CN-SFQ_s.js} +1 -1
  5. package/dist/assets/ScheduledTasksPage-C0htXZk2.js +2 -0
  6. package/dist/assets/SharedConversationPage-CxbAx1fN.js +1 -0
  7. package/dist/assets/TerminalDock-_voUf7d-.js +2 -0
  8. package/dist/assets/WorkspaceInspector-Ci4FuaZH.js +3 -0
  9. package/dist/assets/{WorkspaceReaderDialog-BJo_KEWi.js → WorkspaceReaderDialog-D75__GFg.js} +1 -1
  10. package/dist/assets/diff-line-counts-DHyWKEXk.js +10 -0
  11. package/dist/assets/icons-DzxBk7tb.js +1 -0
  12. package/dist/assets/index-BI7xZuj-.css +3 -0
  13. package/dist/assets/index-BzOV50wA.js +1442 -0
  14. package/dist/assets/{monaco-CGq6uVF1.js → monaco-dMY7_GLO.js} +1 -1
  15. package/dist/assets/{react-vendor-DunfCFfp.js → react-vendor-DsAeMFcm.js} +1 -1
  16. package/dist/index.html +4 -4
  17. package/package.json +1 -1
  18. package/server/acp/server.mjs +1 -0
  19. package/server/agent-manager.mjs +8 -8
  20. package/server/agent-profile-files.mjs +2 -1
  21. package/server/channels/process-channel.mjs +1 -0
  22. package/server/channels/providers/wechat.mjs +1 -0
  23. package/server/custom-commands.mjs +4 -3
  24. package/server/plugins/registry.mjs +1 -1
  25. package/server/project-config.mjs +2 -2
  26. package/server/routes/agent.mjs +0 -1
  27. package/server/routes/project.mjs +3 -2
  28. package/server/routes/scheduled-tasks.mjs +13 -121
  29. package/server/routes/static.mjs +1 -1
  30. package/server/routes/storage.mjs +13 -7
  31. package/server/routes/workspace.mjs +8 -24
  32. package/server/session-utils.mjs +2 -1
  33. package/server/skills.mjs +3 -2
  34. package/server/storage.mjs +0 -1
  35. package/server/tools/index.mjs +5 -2
  36. package/server/utils/logger.mjs +0 -1
  37. package/server/utils/package-update.mjs +2 -2
  38. package/server/utils/scheduled-tasks.mjs +127 -0
  39. package/server/utils/workspace.mjs +1 -1
  40. package/dist/assets/AgentProfilesPage-DUmXUxjA.js +0 -1
  41. package/dist/assets/ChatPanelHost-Syx0SSLe.js +0 -242
  42. package/dist/assets/ScheduledTasksPage-Dw4-tgp9.js +0 -2
  43. package/dist/assets/SharedConversationPage-CaE9bNb9.js +0 -1
  44. package/dist/assets/TerminalDock-BYJcp8Ts.js +0 -2
  45. package/dist/assets/WorkspaceInspector-Bzmv8Cvi.js +0 -3
  46. package/dist/assets/diff-line-counts-BZoYp5ai.js +0 -10
  47. package/dist/assets/icons-47L5YLKz.js +0 -1
  48. package/dist/assets/index-CqfScETb.js +0 -1200
  49. package/dist/assets/index-DzkBgHZf.css +0 -3
@@ -1,4 +1,4 @@
1
- import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{St as t}from"./icons-47L5YLKz.js";function n(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function r(e){if(Array.isArray(e))return e}function i(e,t,n){return(t=p(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=e==null?null:typeof Symbol<`u`&&e[Symbol.iterator]||e[`@@iterator`];if(n!=null){var r,i,a,o,s=[],c=!0,l=!1;try{if(a=(n=n.call(e)).next,t!==0)for(;!(c=(r=a.call(n)).done)&&(s.push(r.value),s.length!==t);c=!0);}catch(e){l=!0,i=e}finally{try{if(!c&&n.return!=null&&(o=n.return(),Object(o)!==o))return}finally{if(l)throw i}}return s}}function o(){throw TypeError(`Invalid attempt to destructure non-iterable instance.
1
+ import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{wt as t}from"./icons-DzxBk7tb.js";function n(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function r(e){if(Array.isArray(e))return e}function i(e,t,n){return(t=p(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=e==null?null:typeof Symbol<`u`&&e[Symbol.iterator]||e[`@@iterator`];if(n!=null){var r,i,a,o,s=[],c=!0,l=!1;try{if(a=(n=n.call(e)).next,t!==0)for(;!(c=(r=a.call(n)).done)&&(s.push(r.value),s.length!==t);c=!0);}catch(e){l=!0,i=e}finally{try{if(!c&&n.return!=null&&(o=n.return(),Object(o)!==o))return}finally{if(l)throw i}}return s}}function o(){throw TypeError(`Invalid attempt to destructure non-iterable instance.
2
2
  In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function c(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?s(Object(n),!0).forEach(function(t){i(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):s(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function l(e,t){if(e==null)return{};var n,r,i=u(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)===-1&&{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function u(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function d(e,t){return r(e)||a(e,t)||m(e,t)||o()}function f(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function p(e){var t=f(e,`string`);return typeof t==`symbol`?t:t+``}function m(e,t){if(e){if(typeof e==`string`)return n(e,t);var r={}.toString.call(e).slice(8,-1);return r===`Object`&&e.constructor&&(r=e.constructor.name),r===`Map`||r===`Set`?Array.from(e):r===`Arguments`||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?n(e,t):void 0}}function h(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function _(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?g(Object(n),!0).forEach(function(t){h(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):g(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function v(){var e=[...arguments];return function(t){return e.reduceRight(function(e,t){return t(e)},t)}}function y(e){return function t(){var n=this,r=[...arguments];return r.length>=e.length?e.apply(this,r):function(){var e=[...arguments];return t.apply(n,[].concat(r,e))}}}function b(e){return{}.toString.call(e).includes(`Object`)}function x(e){return!Object.keys(e).length}function S(e){return typeof e==`function`}function C(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function w(e,t){return b(t)||k(`changeType`),Object.keys(t).some(function(t){return!C(e,t)})&&k(`changeField`),t}function T(e){S(e)||k(`selectorType`)}function E(e){S(e)||b(e)||k(`handlerType`),b(e)&&Object.values(e).some(function(e){return!S(e)})&&k(`handlersType`)}function D(e){e||k(`initialIsRequired`),b(e)||k(`initialType`),x(e)&&k(`initialContent`)}function O(e,t){throw Error(e[t]||e.default)}var k=y(O)({initialIsRequired:`initial state is required`,initialType:`initial state should be an object`,initialContent:`initial state shouldn't be an empty object`,handlerType:`handler should be an object or a function`,handlersType:`all handlers should be a functions`,selectorType:`selector should be a function`,changeType:`provided value of changes should be an object`,changeField:`it seams you want to change a field in the state which is not specified in the "initial" state`,default:"an unknown error accured in `state-local` package"}),A={changes:w,selector:T,handler:E,initial:D};function j(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};A.initial(e),A.handler(t);var n={current:e},r=y(P)(n,t),i=y(N)(n),a=y(A.changes)(e),o=y(M)(n);function s(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:function(e){return e};return A.selector(e),e(n.current)}function c(e){v(r,i,a,o)(e)}return[s,c]}function M(e,t){return S(t)?t(e.current):t}function N(e,t){return e.current=_(_({},e.current),t),t}function P(e,t,n){return S(t)?t(e.current):Object.keys(n).forEach(function(n){return t[n]?.call(t,e.current[n])}),n}var F={create:j},I={paths:{vs:`https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs`}};function ee(e){return function t(){var n=this,r=[...arguments];return r.length>=e.length?e.apply(this,r):function(){var e=[...arguments];return t.apply(n,[].concat(r,e))}}}function te(e){return{}.toString.call(e).includes(`Object`)}function ne(e){return e||R(`configIsRequired`),te(e)||R(`configType`),e.urls?(re(),{paths:{vs:e.urls.monacoBase}}):e}function re(){console.warn(L.deprecation)}function ie(e,t){throw Error(e[t]||e.default)}var L={configIsRequired:`the configuration object is required`,configType:`the configuration object should be an object`,default:"an unknown error accured in `@monaco-editor/loader` package",deprecation:`Deprecation warning!
3
3
  You are using deprecated way of configuration.
4
4
 
@@ -1,4 +1,4 @@
1
- import{t as e}from"./rolldown-runtime-DWdDZTNf.js";import{St as t}from"./icons-47L5YLKz.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-DWdDZTNf.js";import{wt as t}from"./icons-DzxBk7tb.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(`
package/dist/index.html CHANGED
@@ -11,16 +11,16 @@
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-CqfScETb.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-BzOV50wA.js"></script>
15
15
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-DWdDZTNf.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/pi-ai-Cx633yhb.js">
17
17
  <link rel="modulepreload" crossorigin href="/assets/lit-vendor-Dr3cpBGF.js">
18
18
  <link rel="modulepreload" crossorigin href="/assets/pi-web-ui-CBet4bMl.js">
19
19
  <link rel="modulepreload" crossorigin href="/assets/css-utils-rkE68RDy.js">
20
- <link rel="modulepreload" crossorigin href="/assets/icons-47L5YLKz.js">
21
- <link rel="modulepreload" crossorigin href="/assets/react-vendor-DunfCFfp.js">
20
+ <link rel="modulepreload" crossorigin href="/assets/icons-DzxBk7tb.js">
21
+ <link rel="modulepreload" crossorigin href="/assets/react-vendor-DsAeMFcm.js">
22
22
  <link rel="modulepreload" crossorigin href="/assets/logger-B65Akg8A.js">
23
- <link rel="stylesheet" crossorigin href="/assets/index-DzkBgHZf.css">
23
+ <link rel="stylesheet" crossorigin href="/assets/index-BI7xZuj-.css">
24
24
  </head>
25
25
  <body>
26
26
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shawnstack/quickforge",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "AI chat application with Agent access modes for local workspace tools. React + Vite + Tailwind CSS frontend, local Node.js storage server.",
5
5
  "keywords": [
6
6
  "ai",
@@ -889,6 +889,7 @@ export async function createQuickForgeAcpAgent() {
889
889
  }
890
890
  }
891
891
 
892
+ /* eslint-disable no-console -- ACP stdio mode redirects console.log away from stdout protocol traffic. */
892
893
  export async function runQuickForgeAcpStdio() {
893
894
  const originalConsoleLog = console.log
894
895
  console.log = (...args) => console.error(...args)
@@ -34,8 +34,8 @@ import {
34
34
  parseInternalCommandInvocation,
35
35
  resolveCustomCommandInvocation,
36
36
  } from './custom-commands.mjs'
37
- import { omitDetailsForLlm, serverConvertToLlm, messageText, lastAssistantText } from './message-converters.mjs'
38
- import { isPlainObject, mergeQuickForgeTiming, wrapToolDefinition, wrapMcpToolDefinition, wrapPluginToolDefinition, sessionSkillsContext } from './tool-wiring.mjs'
37
+ import { serverConvertToLlm, messageText, lastAssistantText } from './message-converters.mjs'
38
+ import { mergeQuickForgeTiming, wrapToolDefinition, wrapMcpToolDefinition, wrapPluginToolDefinition, sessionSkillsContext } from './tool-wiring.mjs'
39
39
  import {
40
40
  APPROVAL_TIMEOUT_MS,
41
41
  safeReadTools,
@@ -833,8 +833,8 @@ async function runSubagent(parentSession, params, parentSignal, onUpdate) {
833
833
  error.statusCode = 400
834
834
  throw error
835
835
  }
836
- if (!parentSession.projectId || !parentSession.projectContext) {
837
- throw new Error('Subagents require an active project workspace.')
836
+ if (!parentSession.projectContext?.workspaceRoot) {
837
+ throw new Error('Subagents require an active workspace.')
838
838
  }
839
839
  if (!parentSession.model) {
840
840
  throw new Error('No active model is configured for the parent session.')
@@ -866,7 +866,7 @@ async function runSubagent(parentSession, params, parentSignal, onUpdate) {
866
866
  includeMcpTools: false,
867
867
  },
868
868
  )
869
- toolsForClient = tools.map(({ execute, prepareArguments, ...tool }) => tool)
869
+ toolsForClient = tools.map(({ execute: _execute, prepareArguments: _prepareArguments, ...tool }) => tool)
870
870
 
871
871
  const emitSubagentTrace = () => {
872
872
  if (traceTimer) {
@@ -1821,7 +1821,7 @@ export async function abortRun(sessionId) {
1821
1821
  }
1822
1822
 
1823
1823
  // Clean up any pending tool approvals for this session
1824
- for (const [toolCallId, approval] of pendingApprovals) {
1824
+ for (const [_toolCallId, approval] of pendingApprovals) {
1825
1825
  if (approval.sessionId === sessionId) {
1826
1826
  approval.reject(new Error('Run aborted'))
1827
1827
  }
@@ -2014,10 +2014,10 @@ export async function destroyAgent(sessionId) {
2014
2014
  }
2015
2015
 
2016
2016
  // Clean up any pending approvals for this session before removing it.
2017
- for (const [toolCallId, approval] of pendingApprovals) {
2017
+ for (const [_toolCallId, approval] of pendingApprovals) {
2018
2018
  if (approval.sessionId === sessionId) approval.reject(new Error('Session destroyed'))
2019
2019
  }
2020
- for (const [approvalId, approval] of pendingAutoCompactApprovals) {
2020
+ for (const [_approvalId, approval] of pendingAutoCompactApprovals) {
2021
2021
  if (approval.sessionId === sessionId) approval.reject(new Error('Session destroyed'))
2022
2022
  }
2023
2023
 
@@ -2,6 +2,7 @@ import { existsSync, promises as fs } from 'node:fs'
2
2
  import os from 'node:os'
3
3
  import path from 'node:path'
4
4
  import { dataDir } from './storage.mjs'
5
+ import { logger } from './utils/logger.mjs'
5
6
  import { firstOptionalBoolean, firstString, parseFrontmatter, splitDelimitedList } from './frontmatter.mjs'
6
7
 
7
8
  const DEFAULT_MAX_RUNTIME_MS = 30 * 60 * 1000
@@ -123,7 +124,7 @@ async function listAgentFilesFromDirectory(dir, options = {}) {
123
124
  })
124
125
  if (profile) profiles.push(profile)
125
126
  } catch (error) {
126
- console.warn(`Failed to load agent profile ${file}:`, error.message || error)
127
+ logger.warn(`Failed to load agent profile ${file}:`, error.message || error)
127
128
  }
128
129
  }
129
130
  return profiles
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-control-regex -- ANSI escape matching intentionally includes ESC. */
1
2
  import { spawn } from 'node:child_process'
2
3
  import { EventEmitter } from 'node:events'
3
4
  import { setTimeout as delay } from 'node:timers/promises'
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-control-regex -- URL extraction intentionally treats ESC as a delimiter. */
1
2
  import { spawn } from 'node:child_process'
2
3
  import { promises as fs } from 'node:fs'
3
4
  import path from 'node:path'
@@ -2,6 +2,7 @@ import { promises as fs } from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { getEnabledPluginCommandSources } from './plugins/registry.mjs'
4
4
  import { userCommandsDir } from './storage.mjs'
5
+ import { logger } from './utils/logger.mjs'
5
6
 
6
7
  const commandsRelativeDirs = ['.claude/commands', '.opencode/commands', '.ai/commands']
7
8
  const commandsRelativeDir = '.ai/commands'
@@ -239,7 +240,7 @@ async function listCommandsFromDirectory(dir, options = {}) {
239
240
  })
240
241
  if (command) commands.push(command)
241
242
  } catch (error) {
242
- console.warn(`Failed to load custom command ${file}:`, error.message || error)
243
+ logger.warn(`Failed to load custom command ${file}:`, error.message || error)
243
244
  }
244
245
  }
245
246
 
@@ -253,7 +254,7 @@ async function listCommandsFromFile(file, options = {}) {
253
254
  return command ? [command] : []
254
255
  } catch (error) {
255
256
  if (error?.code === 'ENOENT' || error?.code === 'ENOTDIR' || error?.code === 'EACCES' || error?.code === 'EPERM') return []
256
- console.warn(`Failed to load custom command ${file}:`, error.message || error)
257
+ logger.warn(`Failed to load custom command ${file}:`, error.message || error)
257
258
  return []
258
259
  }
259
260
  }
@@ -483,7 +484,7 @@ function formatBuiltinCommandRows() {
483
484
  const aliases = cmd.aliases?.length
484
485
  ? ` (alias: ${cmd.aliases.map((alias) => `/${alias}`).join(', ')})`
485
486
  : ''
486
- const perm = cmd.permissionNote ? ` \[${cmd.permissionNote}\]` : ''
487
+ const perm = cmd.permissionNote ? ` [${cmd.permissionNote}]` : ''
487
488
  return `- \`/${cmd.name}${hint}\`${aliases} — ${cmd.description}${perm}`
488
489
  })
489
490
  }
@@ -43,7 +43,7 @@ async function readJsonFile(filePath) {
43
43
  }
44
44
 
45
45
  async function listPluginDirs(root) {
46
- let entries = []
46
+ let entries
47
47
  try {
48
48
  entries = await fs.readdir(root, { withFileTypes: true })
49
49
  } catch (error) {
@@ -4,7 +4,7 @@ import { randomUUID } from 'node:crypto'
4
4
  import { spawnSync } from 'node:child_process'
5
5
  import { existsSync, promises as fs } from 'node:fs'
6
6
  import { ensureProjectCache, readProjectConfigData, atomicProjectConfigUpdate, dataDir, readStore, atomicUpdate } from './storage.mjs'
7
- import { setWorkspaceRoot, getWorkspaceRoot, assertDirectory } from './utils/workspace.mjs'
7
+ import { setWorkspaceRoot, assertDirectory } from './utils/workspace.mjs'
8
8
  import { loadSelectedGlobalSkills, loadSelectedProjectSkills, mergeSkills } from './skills.mjs'
9
9
 
10
10
  let defaultWorkspaceRoot = ''
@@ -101,7 +101,7 @@ function terminalShellProfileCandidatesForPlatform(platform = os.platform()) {
101
101
  const profiles = TERMINAL_SHELL_PROFILE_CANDIDATES
102
102
  .filter((profile) => profile.platforms.includes(platform))
103
103
  .filter((profile) => commandExists(profile.command))
104
- .map(({ platforms, ...profile }) => ({ ...profile, builtin: true, detected: true }))
104
+ .map(({ platforms: _platforms, ...profile }) => ({ ...profile, builtin: true, detected: true }))
105
105
 
106
106
  return profiles
107
107
  }
@@ -15,7 +15,6 @@ import {
15
15
  restoreAgent,
16
16
  touchSession,
17
17
  listSessions,
18
- refreshAllSessionTools,
19
18
  updateSessionAccessMode,
20
19
  updateSessionYoloMode,
21
20
  updateSessionModel,
@@ -1,4 +1,5 @@
1
1
  import { sendJson, readJsonBody, decodeSegment } from '../utils/response.mjs'
2
+ import { logger } from '../utils/logger.mjs'
2
3
  import { getActiveProject, setActiveProjectPath, readProjectConfig, getDefaultWorkspaceRoot } from '../project-config.mjs'
3
4
  import { listProjectCommands, createCommandFile } from '../custom-commands.mjs'
4
5
  import { atomicProjectConfigUpdate } from '../storage.mjs'
@@ -38,9 +39,9 @@ export async function handleProjectApi(req, res, url) {
38
39
  }
39
40
 
40
41
  if (req.method === 'POST' && url.pathname === '/api/project/select-directory') {
41
- console.log('[project] Opening directory picker dialog...')
42
+ logger.info('[project] Opening directory picker dialog...')
42
43
  const selectedPath = await selectDirectoryDialog()
43
- console.log('[project] Directory picker result:', selectedPath ? `"${selectedPath}"` : '(cancelled/empty)')
44
+ logger.info('[project] Directory picker result', { selectedPath: selectedPath || null })
44
45
  if (!selectedPath) {
45
46
  sendJson(res, 200, { cancelled: true, project: getActiveProject(config), projects: config.projects })
46
47
  return
@@ -5,14 +5,24 @@ import { createAgent, getSessionEventBus, agentEvents, persistSessionState } fro
5
5
  import { agentProfileSnapshot, getAgentProfile } from '../agent-profiles.mjs'
6
6
  import { projectContextFromId, readProjectConfig } from '../project-config.mjs'
7
7
  import { logger } from '../utils/logger.mjs'
8
+ import {
9
+ dayMs,
10
+ formatLocalDateTime,
11
+ hourMs,
12
+ minuteMs,
13
+ nextCronRun,
14
+ nextDailyRun,
15
+ nextMonthlyRun,
16
+ nextWeeklyRun,
17
+ normalizeExecutionMode,
18
+ parseExecuteTime,
19
+ timeFromDate,
20
+ } from '../utils/scheduled-tasks.mjs'
8
21
 
9
22
  const STORE = 'scheduled-tasks'
10
23
  const RUN_CHECK_INTERVAL_MS = 30 * 1000
11
24
  const MAX_RUN_HISTORY_PER_TASK = 200
12
25
  const cronRegex = /^(\*|\d{1,2}|\d{1,2}-\d{1,2}|\d{1,2}\/\d{1,2}|\*\/\d{1,2})(\s+(\*|\d{1,2}|\d{1,2}-\d{1,2}|\d{1,2}\/\d{1,2}|\*\/\d{1,2})){4}$/
13
- const minuteMs = 60 * 1000
14
- const hourMs = 60 * minuteMs
15
- const dayMs = 24 * hourMs
16
26
  const editableScheduleTypes = new Set(['once', 'daily', 'weekly', 'monthly'])
17
27
  const weekDayNames = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
18
28
 
@@ -24,13 +34,6 @@ function executionModeFor(task) {
24
34
  return task?.executionMode === 'parallel' ? 'parallel' : 'serial'
25
35
  }
26
36
 
27
- function normalizeExecutionMode(value) {
28
- if (value === undefined || value === null || value === '') return 'serial'
29
- const mode = String(value)
30
- if (mode === 'serial' || mode === 'parallel') return mode
31
- throw requestError('executionMode must be serial or parallel')
32
- }
33
-
34
37
  function currentRunIdsFor(task) {
35
38
  const ids = []
36
39
  if (Array.isArray(task?.currentRunIds)) ids.push(...task.currentRunIds.filter(Boolean))
@@ -72,20 +75,6 @@ function createId() {
72
75
  return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`
73
76
  }
74
77
 
75
- function pad(value) {
76
- return String(value).padStart(2, '0')
77
- }
78
-
79
- function formatLocalDateTime(date) {
80
- return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`
81
- }
82
-
83
- function timeFromDate(value) {
84
- const date = value ? new Date(value) : null
85
- if (!date || Number.isNaN(date.getTime())) return undefined
86
- return `${pad(date.getHours())}:${pad(date.getMinutes())}`
87
- }
88
-
89
78
  function requestError(message, statusCode = 400) {
90
79
  const error = new Error(message)
91
80
  error.statusCode = statusCode
@@ -98,67 +87,12 @@ function nonEmptyString(value, fieldName) {
98
87
  return text
99
88
  }
100
89
 
101
- function parseExecuteTime(value) {
102
- const text = String(value ?? '').trim()
103
- const match = text.match(/^(\d{1,2}):(\d{2})$/)
104
- if (!match) throw requestError('executeTime must use HH:mm format')
105
- const hours = Number(match[1])
106
- const minutes = Number(match[2])
107
- if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {
108
- throw requestError('executeTime is out of range')
109
- }
110
- return `${pad(hours)}:${pad(minutes)}`
111
- }
112
-
113
- function dateWithTime(base, executeTime) {
114
- const [hours, minutes] = parseExecuteTime(executeTime).split(':').map(Number)
115
- const date = new Date(base)
116
- date.setHours(hours, minutes, 0, 0)
117
- return date
118
- }
119
-
120
90
  function parseDateTime(value, fieldName) {
121
91
  const date = new Date(value)
122
92
  if (Number.isNaN(date.getTime())) throw requestError(`${fieldName} is invalid`)
123
93
  return date
124
94
  }
125
95
 
126
- function nextDailyRun(executeTime, base = new Date()) {
127
- const next = dateWithTime(base, executeTime)
128
- if (next.getTime() <= base.getTime()) next.setDate(next.getDate() + 1)
129
- return next
130
- }
131
-
132
- function nextWeeklyRun(weekDay, executeTime, base = new Date()) {
133
- const targetDay = Number(weekDay)
134
- if (!Number.isInteger(targetDay) || targetDay < 0 || targetDay > 6) {
135
- throw requestError('weekDay must be between 0 and 6')
136
- }
137
- const next = dateWithTime(base, executeTime)
138
- let daysToAdd = (targetDay - next.getDay() + 7) % 7
139
- if (daysToAdd === 0 && next.getTime() <= base.getTime()) daysToAdd = 7
140
- next.setDate(next.getDate() + daysToAdd)
141
- return next
142
- }
143
-
144
- function monthlyCandidate(year, month, monthDay, executeTime) {
145
- const targetDay = Number(monthDay)
146
- if (!Number.isInteger(targetDay) || targetDay < 1 || targetDay > 31) {
147
- throw requestError('monthDay must be between 1 and 31')
148
- }
149
- const [hours, minutes] = parseExecuteTime(executeTime).split(':').map(Number)
150
- const lastDay = new Date(year, month + 1, 0).getDate()
151
- return new Date(year, month, Math.min(targetDay, lastDay), hours, minutes, 0, 0)
152
- }
153
-
154
- function nextMonthlyRun(monthDay, executeTime, base = new Date()) {
155
- let next = monthlyCandidate(base.getFullYear(), base.getMonth(), monthDay, executeTime)
156
- if (next.getTime() <= base.getTime()) {
157
- next = monthlyCandidate(base.getFullYear(), base.getMonth() + 1, monthDay, executeTime)
158
- }
159
- return next
160
- }
161
-
162
96
  function scheduleRuleFor(task) {
163
97
  if (task.scheduleType === 'once') return `单次 ${formatLocalDateTime(new Date(task.executeAt ?? task.nextRunAt))}`
164
98
  if (task.scheduleType === 'daily') return `每天 ${task.executeTime}`
@@ -167,48 +101,6 @@ function scheduleRuleFor(task) {
167
101
  return task.scheduleRule || task.cronExpression || '定时执行'
168
102
  }
169
103
 
170
- function parseCronField(field, min, max) {
171
- if (field === '*') return { any: true, values: [] }
172
- const values = new Set()
173
- for (const part of field.split(',')) {
174
- if (/^\*\/\d+$/.test(part)) {
175
- const step = Number(part.slice(2))
176
- for (let value = min; value <= max; value += step) values.add(value)
177
- } else if (/^\d+-\d+$/.test(part)) {
178
- const [start, end] = part.split('-').map(Number)
179
- for (let value = Math.max(start, min); value <= Math.min(end, max); value += 1) values.add(value)
180
- } else if (/^\d+$/.test(part)) {
181
- const value = Number(part)
182
- if (value >= min && value <= max) values.add(value)
183
- }
184
- }
185
- return { any: false, values: [...values] }
186
- }
187
-
188
- function cronMatches(date, cronExpression) {
189
- const fields = String(cronExpression || '').trim().split(/\s+/)
190
- if (fields.length !== 5) return false
191
- const checks = [
192
- [date.getMinutes(), parseCronField(fields[0], 0, 59)],
193
- [date.getHours(), parseCronField(fields[1], 0, 23)],
194
- [date.getDate(), parseCronField(fields[2], 1, 31)],
195
- [date.getMonth() + 1, parseCronField(fields[3], 1, 12)],
196
- [date.getDay(), parseCronField(fields[4], 0, 6)],
197
- ]
198
- return checks.every(([value, rule]) => rule.any || rule.values.includes(value))
199
- }
200
-
201
- function nextCronRun(cronExpression, base = new Date()) {
202
- const cursor = new Date(base.getTime() + minuteMs)
203
- cursor.setSeconds(0, 0)
204
- const maxChecks = 366 * 24 * 60
205
- for (let index = 0; index < maxChecks; index += 1) {
206
- if (cronMatches(cursor, cronExpression)) return cursor
207
- cursor.setMinutes(cursor.getMinutes() + 1)
208
- }
209
- return null
210
- }
211
-
212
104
  function normalizeAiJson(text) {
213
105
  const raw = String(text || '').trim()
214
106
  const fenced = raw.match(/```(?:json)?\s*([\s\S]*?)```/i)
@@ -48,7 +48,7 @@ function shouldFallbackToIndex(url, pathname) {
48
48
  export async function serveStatic(req, res, url) {
49
49
  const distDir = path.join(projectRoot, 'dist')
50
50
  const requested = decodeURIComponent(requestPathname(url))
51
- const normalized = path.normalize(requested).replace(/^([.][.][\/])+/, '').replace(/^[/\\]+/, '')
51
+ const normalized = path.normalize(requested).replace(/^([.][.][/])+/, '').replace(/^[/\\]+/, '')
52
52
  let filePath = path.resolve(distDir, normalized)
53
53
 
54
54
  const relative = path.relative(distDir, filePath)
@@ -1,4 +1,3 @@
1
- import path from 'node:path'
2
1
  import { sendJson, readJsonBody, decodeSegment } from '../utils/response.mjs'
3
2
  import { readStore, writeStore, atomicUpdate, getComparable, getStoreRevision, readSessionStoreScoped, readSessionValue, writeSessionValue, deleteSessionValue, ensureStorage, dataDir, configDir, storageDir, cacheDir, logsDir } from '../storage.mjs'
4
3
  import { directorySize } from '../utils/workspace.mjs'
@@ -7,8 +6,8 @@ const metadataIndexCache = new Map()
7
6
  const MAX_METADATA_INDEX_CACHE_ENTRIES = 50
8
7
  const METADATA_INDEX_CACHE_TTL_MS = 1000
9
8
 
10
- function metadataIndexCacheKey({ scope, projectId, indexName, direction }) {
11
- return JSON.stringify({ scope: scope || '', projectId: projectId || '', indexName, direction })
9
+ function metadataIndexCacheKey({ scope, projectId, indexName, direction, archived }) {
10
+ return JSON.stringify({ scope: scope || '', projectId: projectId || '', indexName, direction, archived: archived || '' })
12
11
  }
13
12
 
14
13
  function sortIndexedValues(values, store, indexName, direction) {
@@ -34,7 +33,7 @@ function sortIndexedValues(values, store, indexName, direction) {
34
33
  return values
35
34
  }
36
35
 
37
- async function readIndexedValues(store, indexName, direction, scope, projectId) {
36
+ async function readIndexedValues(store, indexName, direction, scope, projectId, archived) {
38
37
  if (store !== 'sessions-metadata') {
39
38
  let data
40
39
  if (scope && store === 'sessions') {
@@ -46,7 +45,7 @@ async function readIndexedValues(store, indexName, direction, scope, projectId)
46
45
  }
47
46
 
48
47
  const revision = getStoreRevision(store)
49
- const key = metadataIndexCacheKey({ scope, projectId, indexName, direction })
48
+ const key = metadataIndexCacheKey({ scope, projectId, indexName, direction, archived })
50
49
  const cached = metadataIndexCache.get(key)
51
50
  const now = Date.now()
52
51
  if (cached && cached.revision === revision && now - cached.cachedAt < METADATA_INDEX_CACHE_TTL_MS) return cached.values
@@ -55,7 +54,13 @@ async function readIndexedValues(store, indexName, direction, scope, projectId)
55
54
  ? await readSessionStoreScoped(store, scope, scope === 'project' ? projectId : undefined)
56
55
  : await readStore(store)
57
56
  const values = sortIndexedValues(
58
- Object.values(data).filter((value) => value?.messageCount !== 0),
57
+ Object.values(data)
58
+ .filter((value) => value?.messageCount !== 0)
59
+ .filter((value) => {
60
+ if (archived === 'only') return Boolean(value?.archivedAt)
61
+ if (archived === 'include') return true
62
+ return !value?.archivedAt
63
+ }),
59
64
  store,
60
65
  indexName,
61
66
  direction,
@@ -107,10 +112,11 @@ export async function handleStorageApi(req, res, url) {
107
112
  const projectId = url.searchParams.get('projectId')
108
113
  const limitParam = url.searchParams.get('limit')
109
114
  const offsetParam = url.searchParams.get('offset')
115
+ const archived = url.searchParams.get('archived')
110
116
 
111
117
  await ensureStorage()
112
118
 
113
- const values = await readIndexedValues(store, indexName, direction, scope, projectId)
119
+ const values = await readIndexedValues(store, indexName, direction, scope, projectId, archived)
114
120
 
115
121
  const total = values.length
116
122
  const limit = limitParam ? parseInt(limitParam, 10) : undefined
@@ -5,17 +5,15 @@ import { sendJson, readJsonBody } from '../utils/response.mjs'
5
5
  import { projectContextFromId } from '../project-config.mjs'
6
6
  import {
7
7
  assertSafeWorkspacePath,
8
- isSensitiveWorkspacePath,
9
8
  resolveWorkspacePath,
10
- shouldSearchFile,
11
9
  toWorkspaceRelative,
12
10
  } from '../utils/workspace.mjs'
13
11
 
14
- const MAX_PREVIEW_BYTES = 1024 * 1024
15
- const MAX_STATIC_PREVIEW_BYTES = 10 * 1024 * 1024
12
+ const MAX_PREVIEW_BYTES = 50 * 1024 * 1024
13
+ const MAX_STATIC_PREVIEW_BYTES = 50 * 1024 * 1024
16
14
  const PREVIEW_ALLOWED_EXTENSIONS = new Set(['.html', '.htm', '.css', '.js', '.mjs', '.json', '.svg', '.png', '.jpg', '.jpeg', '.webp', '.gif', '.ico', '.txt', '.md'])
17
- const MAX_TREE_NODES = 5000
18
- const SKIP_DIRS = new Set(['.git', 'node_modules', 'dist', 'dist-ssr', 'package-dist', 'package-offline', '.vite', 'coverage'])
15
+ const MAX_TREE_NODES = 50000
16
+ const SKIP_DIRS = new Set(['.git', 'node_modules'])
19
17
 
20
18
  const extensionLanguageMap = new Map([
21
19
  ['ts', 'typescript'], ['tsx', 'typescript'], ['js', 'javascript'], ['jsx', 'javascript'],
@@ -58,14 +56,6 @@ function previewContentType(filePath) {
58
56
  return map[ext] || 'application/octet-stream'
59
57
  }
60
58
 
61
- function isBinaryBuffer(buffer) {
62
- const length = Math.min(buffer.length, 8000)
63
- for (let index = 0; index < length; index += 1) {
64
- if (buffer[index] === 0) return true
65
- }
66
- return false
67
- }
68
-
69
59
  async function projectContextFromUrl(url) {
70
60
  const projectId = url.searchParams.get('projectId')
71
61
  if (!projectId) {
@@ -248,7 +238,7 @@ async function readGitFile(workspaceRoot, ref, relativePath) {
248
238
 
249
239
  async function readWorkspaceTextFile(context, relativePath) {
250
240
  const file = resolveWorkspacePath(relativePath, context)
251
- await assertSafeWorkspacePath(file, context)
241
+ await assertSafeWorkspacePath(file, context, { allowSensitive: true })
252
242
  const stat = await fs.stat(file)
253
243
  if (!stat.isFile()) {
254
244
  const error = new Error('Path is not a file')
@@ -261,11 +251,6 @@ async function readWorkspaceTextFile(context, relativePath) {
261
251
  throw error
262
252
  }
263
253
  const buffer = await fs.readFile(file)
264
- if (isBinaryBuffer(buffer)) {
265
- const error = new Error('Binary file cannot be previewed')
266
- error.statusCode = 415
267
- throw error
268
- }
269
254
  return { content: buffer.toString('utf8'), size: stat.size, path: toWorkspaceRelative(file, context) }
270
255
  }
271
256
 
@@ -282,9 +267,9 @@ async function buildTreeForDirectory(dir, context, counter) {
282
267
  const fullPath = path.join(dir, entry.name)
283
268
  const relativePath = toWorkspaceRelative(fullPath, context)
284
269
  if (entry.isDirectory()) {
285
- if (SKIP_DIRS.has(entry.name) || isSensitiveWorkspacePath(fullPath, context)) continue
270
+ if (SKIP_DIRS.has(entry.name)) continue
286
271
  try {
287
- await assertSafeWorkspacePath(fullPath, context)
272
+ await assertSafeWorkspacePath(fullPath, context, { allowSensitive: true })
288
273
  counter.count += 1
289
274
  nodes.push({
290
275
  name: entry.name,
@@ -296,9 +281,8 @@ async function buildTreeForDirectory(dir, context, counter) {
296
281
  // Skip directories that cannot be safely resolved.
297
282
  }
298
283
  } else if (entry.isFile()) {
299
- if (!shouldSearchFile(entry.name) || isSensitiveWorkspacePath(fullPath, context)) continue
300
284
  try {
301
- await assertSafeWorkspacePath(fullPath, context)
285
+ await assertSafeWorkspacePath(fullPath, context, { allowSensitive: true })
302
286
  counter.count += 1
303
287
  nodes.push({ name: entry.name, path: relativePath, type: 'file' })
304
288
  } catch {
@@ -2,6 +2,7 @@ import { streamSimple } from '@earendil-works/pi-ai'
2
2
  import { buildInstructionsPayload, projectContextFromId } from './project-config.mjs'
3
3
  import { composeSystemPrompt } from './system-prompt.mjs'
4
4
  import { listSubagentProfiles } from './agent-profiles.mjs'
5
+ import { logger } from './utils/logger.mjs'
5
6
 
6
7
  // ---------------------------------------------------------------------------
7
8
  // System prompt
@@ -109,7 +110,7 @@ export async function generateAiTitle(messages, model, thinkingLevel, getApiKey)
109
110
  const title = normalizeAiTitle(titleText)
110
111
  return title || null
111
112
  } catch (error) {
112
- console.warn('Failed to generate AI title:', error.message || error)
113
+ logger.warn('Failed to generate AI title:', error.message || error)
113
114
  return null
114
115
  }
115
116
  }