@vibe-forge/client 0.2.0-alpha.8 → 0.3.0

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 (60) hide show
  1. package/dist/assets/{arc-CybT1Fs2.js → arc-CwMXUVsq.js} +1 -1
  2. package/dist/assets/{blockDiagram-c4efeb88-BY5Aoa-D.js → blockDiagram-c4efeb88-CGxJV7KJ.js} +1 -1
  3. package/dist/assets/{c4Diagram-c83219d4-F42hTbzS.js → c4Diagram-c83219d4-BKhin7cY.js} +1 -1
  4. package/dist/assets/channel-jbCEHqbG.js +1 -0
  5. package/dist/assets/{classDiagram-beda092f-D-tIPp-3.js → classDiagram-beda092f-BASmn22R.js} +1 -1
  6. package/dist/assets/{classDiagram-v2-2358418a-J57aCe6u.js → classDiagram-v2-2358418a-BUk9rNBX.js} +1 -1
  7. package/dist/assets/clone-CCRKqS4L.js +1 -0
  8. package/dist/assets/{createText-1719965b-ByfEqOF-.js → createText-1719965b-2XqnWjQY.js} +1 -1
  9. package/dist/assets/{edges-96097737-CMEArkOa.js → edges-96097737-B7e32Jeg.js} +1 -1
  10. package/dist/assets/{erDiagram-0228fc6a-Cf8mX2aj.js → erDiagram-0228fc6a-CCR2or72.js} +1 -1
  11. package/dist/assets/{flowDb-c6c81e3f-DG6WKyo7.js → flowDb-c6c81e3f-B72HWT9x.js} +1 -1
  12. package/dist/assets/{flowDiagram-50d868cf-CstUxz-w.js → flowDiagram-50d868cf-WOi0KARY.js} +1 -1
  13. package/dist/assets/flowDiagram-v2-4f6560a1-Baslbgn4.js +1 -0
  14. package/dist/assets/{flowchart-elk-definition-6af322e1--4CRoQ-H.js → flowchart-elk-definition-6af322e1-i_Yd0LCE.js} +1 -1
  15. package/dist/assets/{ganttDiagram-a2739b55-DYgHcKd-.js → ganttDiagram-a2739b55-CFH9zF14.js} +1 -1
  16. package/dist/assets/{gitGraphDiagram-82fe8481-DDSVpfsd.js → gitGraphDiagram-82fe8481-DglKfMze.js} +1 -1
  17. package/dist/assets/{graph-CRWF39gX.js → graph-BKbBNGPf.js} +1 -1
  18. package/dist/assets/{index-5325376f-W1hft795.js → index-5325376f-BK7F9nSl.js} +1 -1
  19. package/dist/assets/{index-PEmISxiy.css → index-B0qfCb1G.css} +1 -1
  20. package/dist/assets/{index-CNMzWvKV.js → index-CNo75dYr.js} +127 -127
  21. package/dist/assets/{infoDiagram-8eee0895-D4SHcix6.js → infoDiagram-8eee0895-BLFL77_D.js} +1 -1
  22. package/dist/assets/{journeyDiagram-c64418c1-MWgCkVoE.js → journeyDiagram-c64418c1-CS9XctDL.js} +1 -1
  23. package/dist/assets/{layout-C88ObkCf.js → layout-By3JZZGt.js} +1 -1
  24. package/dist/assets/{line-C7WAYMt5.js → line-9GUsXbwv.js} +1 -1
  25. package/dist/assets/{linear-C4msxfcU.js → linear-DzGV4E9N.js} +1 -1
  26. package/dist/assets/{mermaid.core-Cabag9SZ.js → mermaid.core-CG3Ib42Q.js} +4 -4
  27. package/dist/assets/{mindmap-definition-8da855dc-CeS8ETXx.js → mindmap-definition-8da855dc-WQ3LPKJU.js} +1 -1
  28. package/dist/assets/{pieDiagram-a8764435-BvjyKnq5.js → pieDiagram-a8764435-DHVIUZiN.js} +1 -1
  29. package/dist/assets/{quadrantDiagram-1e28029f-DzYvpbNM.js → quadrantDiagram-1e28029f-C3G9Ye8-.js} +1 -1
  30. package/dist/assets/{requirementDiagram-08caed73-DHIoDbyo.js → requirementDiagram-08caed73-C9ES1D5G.js} +1 -1
  31. package/dist/assets/{sankeyDiagram-a04cb91d-BFSGnQGs.js → sankeyDiagram-a04cb91d-B4BKXclQ.js} +1 -1
  32. package/dist/assets/{sequenceDiagram-c5b8d532-_LM3BJ5-.js → sequenceDiagram-c5b8d532-DrgEb25G.js} +1 -1
  33. package/dist/assets/{stateDiagram-1ecb1508-DwORjOzl.js → stateDiagram-1ecb1508-CF1XWARJ.js} +1 -1
  34. package/dist/assets/{stateDiagram-v2-c2b004d7-B4cAWWz1.js → stateDiagram-v2-c2b004d7-IO3i3yXv.js} +1 -1
  35. package/dist/assets/{styles-b4e223ce-D_rmV3B_.js → styles-b4e223ce-DACN9aSc.js} +1 -1
  36. package/dist/assets/{styles-ca3715f6-BFx4VuFc.js → styles-ca3715f6-bekm2WLP.js} +1 -1
  37. package/dist/assets/{styles-d45a18b0-BE3106vL.js → styles-d45a18b0-OzTDVBb8.js} +1 -1
  38. package/dist/assets/{svgDrawCommon-b86b1483-DwDTO1op.js → svgDrawCommon-b86b1483-BWroJerr.js} +1 -1
  39. package/dist/assets/{timeline-definition-faaaa080-C4b8qUQZ.js → timeline-definition-faaaa080-CCfRNigO.js} +1 -1
  40. package/dist/assets/{xychartDiagram-f5964ef8-BRJ9Z4u-.js → xychartDiagram-f5964ef8-C3cbfVqN.js} +1 -1
  41. package/dist/index.html +2 -2
  42. package/package.json +3 -3
  43. package/src/api.ts +30 -2
  44. package/src/components/ConfigView.tsx +6 -1
  45. package/src/components/chat/NewSessionGuide.scss +35 -13
  46. package/src/components/chat/NewSessionGuide.tsx +20 -10
  47. package/src/components/chat/useChatModels.tsx +19 -1
  48. package/src/components/chat/useChatSession.ts +1 -1
  49. package/src/components/config/AppSettingsPanel.tsx +33 -0
  50. package/src/components/knowledge-base/KnowledgeBaseView.tsx +51 -3
  51. package/src/components/knowledge-base/components/RuleItem.tsx +79 -0
  52. package/src/components/knowledge-base/components/RuleList.scss +5 -0
  53. package/src/components/knowledge-base/components/RuleList.tsx +70 -0
  54. package/src/components/knowledge-base/components/RulesTab.tsx +32 -7
  55. package/src/resources/locales/en.json +7 -0
  56. package/src/resources/locales/zh.json +7 -0
  57. package/src/store/index.ts +2 -0
  58. package/dist/assets/channel-DrWdSpqV.js +0 -1
  59. package/dist/assets/clone-D0cC8LLB.js +0 -1
  60. package/dist/assets/flowDiagram-v2-4f6560a1-Bf_DH7dp.js +0 -1
@@ -1,4 +1,4 @@
1
- import{s as zt,a as Ft,v as wt,x as Nt,b as Xt,c as Yt,l as St,aH as Ht,e as $t,z as Ut,ap as ot,aJ as Ct,aL as qt,aY as jt,i as Gt}from"./mermaid.core-Cabag9SZ.js";import{a as Qt}from"./createText-1719965b-ByfEqOF-.js";import"./index-CNMzWvKV.js";import{i as Kt}from"./init-Gi6I4Gst.js";import{o as Jt}from"./ordinal-Cboi1Yqb.js";import{l as ft}from"./linear-C4msxfcU.js";import{l as pt}from"./line-C7WAYMt5.js";import"./array-BKyUJesY.js";import"./path-CbwjOpE9.js";function Zt(e,t,i){e=+e,t=+t,i=(n=arguments.length)<2?(t=e,e=0,1):n<3?1:+i;for(var s=-1,n=Math.max(0,Math.ceil((t-e)/i))|0,o=new Array(n);++s<n;)o[s]=e+s*i;return o}function st(){var e=Jt().unknown(void 0),t=e.domain,i=e.range,s=0,n=1,o,c,f=!1,d=0,R=0,_=.5;delete e.unknown;function A(){var m=t().length,T=n<s,S=T?n:s,P=T?s:n;o=(P-S)/Math.max(1,m-d+R*2),f&&(o=Math.floor(o)),S+=(P-S-o*(m-d))*_,c=o*(1-d),f&&(S=Math.round(S),c=Math.round(c));var p=Zt(m).map(function(C){return S+o*C});return i(T?p.reverse():p)}return e.domain=function(m){return arguments.length?(t(m),A()):t()},e.range=function(m){return arguments.length?([s,n]=m,s=+s,n=+n,A()):[s,n]},e.rangeRound=function(m){return[s,n]=m,s=+s,n=+n,f=!0,A()},e.bandwidth=function(){return c},e.step=function(){return o},e.round=function(m){return arguments.length?(f=!!m,A()):f},e.padding=function(m){return arguments.length?(d=Math.min(1,R=+m),A()):d},e.paddingInner=function(m){return arguments.length?(d=Math.min(1,m),A()):d},e.paddingOuter=function(m){return arguments.length?(R=+m,A()):R},e.align=function(m){return arguments.length?(_=Math.max(0,Math.min(1,m)),A()):_},e.copy=function(){return st(t(),[s,n]).round(f).paddingInner(d).paddingOuter(R).align(_)},Kt.apply(A(),arguments)}var nt=function(){var e=function(V,r,l,u){for(l=l||{},u=V.length;u--;l[V[u]]=r);return l},t=[1,10,12,14,16,18,19,21,23],i=[2,6],s=[1,3],n=[1,5],o=[1,6],c=[1,7],f=[1,5,10,12,14,16,18,19,21,23,34,35,36],d=[1,25],R=[1,26],_=[1,28],A=[1,29],m=[1,30],T=[1,31],S=[1,32],P=[1,33],p=[1,34],C=[1,35],h=[1,36],L=[1,37],z=[1,43],lt=[1,42],ct=[1,47],$=[1,50],w=[1,10,12,14,16,18,19,21,23,34,35,36],Q=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36],v=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36,41,42,43,44,45,46,47,48,49,50],ut=[1,64],K={trace:function(){},yy:{},symbols_:{error:2,start:3,eol:4,XYCHART:5,chartConfig:6,document:7,CHART_ORIENTATION:8,statement:9,title:10,text:11,X_AXIS:12,parseXAxis:13,Y_AXIS:14,parseYAxis:15,LINE:16,plotData:17,BAR:18,acc_title:19,acc_title_value:20,acc_descr:21,acc_descr_value:22,acc_descr_multiline_value:23,SQUARE_BRACES_START:24,commaSeparatedNumbers:25,SQUARE_BRACES_END:26,NUMBER_WITH_DECIMAL:27,COMMA:28,xAxisData:29,bandData:30,ARROW_DELIMITER:31,commaSeparatedTexts:32,yAxisData:33,NEWLINE:34,SEMI:35,EOF:36,alphaNum:37,STR:38,MD_STR:39,alphaNumToken:40,AMP:41,NUM:42,ALPHA:43,PLUS:44,EQUALS:45,MULT:46,DOT:47,BRKT:48,MINUS:49,UNDERSCORE:50,$accept:0,$end:1},terminals_:{2:"error",5:"XYCHART",8:"CHART_ORIENTATION",10:"title",12:"X_AXIS",14:"Y_AXIS",16:"LINE",18:"BAR",19:"acc_title",20:"acc_title_value",21:"acc_descr",22:"acc_descr_value",23:"acc_descr_multiline_value",24:"SQUARE_BRACES_START",26:"SQUARE_BRACES_END",27:"NUMBER_WITH_DECIMAL",28:"COMMA",31:"ARROW_DELIMITER",34:"NEWLINE",35:"SEMI",36:"EOF",38:"STR",39:"MD_STR",41:"AMP",42:"NUM",43:"ALPHA",44:"PLUS",45:"EQUALS",46:"MULT",47:"DOT",48:"BRKT",49:"MINUS",50:"UNDERSCORE"},productions_:[0,[3,2],[3,3],[3,2],[3,1],[6,1],[7,0],[7,2],[9,2],[9,2],[9,2],[9,2],[9,2],[9,3],[9,2],[9,3],[9,2],[9,2],[9,1],[17,3],[25,3],[25,1],[13,1],[13,2],[13,1],[29,1],[29,3],[30,3],[32,3],[32,1],[15,1],[15,2],[15,1],[33,3],[4,1],[4,1],[4,1],[11,1],[11,1],[11,1],[37,1],[37,2],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1]],performAction:function(r,l,u,g,b,a,F){var x=a.length-1;switch(b){case 5:g.setOrientation(a[x]);break;case 9:g.setDiagramTitle(a[x].text.trim());break;case 12:g.setLineData({text:"",type:"text"},a[x]);break;case 13:g.setLineData(a[x-1],a[x]);break;case 14:g.setBarData({text:"",type:"text"},a[x]);break;case 15:g.setBarData(a[x-1],a[x]);break;case 16:this.$=a[x].trim(),g.setAccTitle(this.$);break;case 17:case 18:this.$=a[x].trim(),g.setAccDescription(this.$);break;case 19:this.$=a[x-1];break;case 20:this.$=[Number(a[x-2]),...a[x]];break;case 21:this.$=[Number(a[x])];break;case 22:g.setXAxisTitle(a[x]);break;case 23:g.setXAxisTitle(a[x-1]);break;case 24:g.setXAxisTitle({type:"text",text:""});break;case 25:g.setXAxisBand(a[x]);break;case 26:g.setXAxisRangeData(Number(a[x-2]),Number(a[x]));break;case 27:this.$=a[x-1];break;case 28:this.$=[a[x-2],...a[x]];break;case 29:this.$=[a[x]];break;case 30:g.setYAxisTitle(a[x]);break;case 31:g.setYAxisTitle(a[x-1]);break;case 32:g.setYAxisTitle({type:"text",text:""});break;case 33:g.setYAxisRangeData(Number(a[x-2]),Number(a[x]));break;case 37:this.$={text:a[x],type:"text"};break;case 38:this.$={text:a[x],type:"text"};break;case 39:this.$={text:a[x],type:"markdown"};break;case 40:this.$=a[x];break;case 41:this.$=a[x-1]+""+a[x];break}},table:[e(t,i,{3:1,4:2,7:4,5:s,34:n,35:o,36:c}),{1:[3]},e(t,i,{4:2,7:4,3:8,5:s,34:n,35:o,36:c}),e(t,i,{4:2,7:4,6:9,3:10,5:s,8:[1,11],34:n,35:o,36:c}),{1:[2,4],9:12,10:[1,13],12:[1,14],14:[1,15],16:[1,16],18:[1,17],19:[1,18],21:[1,19],23:[1,20]},e(f,[2,34]),e(f,[2,35]),e(f,[2,36]),{1:[2,1]},e(t,i,{4:2,7:4,3:21,5:s,34:n,35:o,36:c}),{1:[2,3]},e(f,[2,5]),e(t,[2,7],{4:22,34:n,35:o,36:c}),{11:23,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:39,13:38,24:z,27:lt,29:40,30:41,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:45,15:44,27:ct,33:46,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:49,17:48,24:$,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:52,17:51,24:$,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{20:[1,53]},{22:[1,54]},e(w,[2,18]),{1:[2,2]},e(w,[2,8]),e(w,[2,9]),e(Q,[2,37],{40:55,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L}),e(Q,[2,38]),e(Q,[2,39]),e(v,[2,40]),e(v,[2,42]),e(v,[2,43]),e(v,[2,44]),e(v,[2,45]),e(v,[2,46]),e(v,[2,47]),e(v,[2,48]),e(v,[2,49]),e(v,[2,50]),e(v,[2,51]),e(w,[2,10]),e(w,[2,22],{30:41,29:56,24:z,27:lt}),e(w,[2,24]),e(w,[2,25]),{31:[1,57]},{11:59,32:58,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},e(w,[2,11]),e(w,[2,30],{33:60,27:ct}),e(w,[2,32]),{31:[1,61]},e(w,[2,12]),{17:62,24:$},{25:63,27:ut},e(w,[2,14]),{17:65,24:$},e(w,[2,16]),e(w,[2,17]),e(v,[2,41]),e(w,[2,23]),{27:[1,66]},{26:[1,67]},{26:[2,29],28:[1,68]},e(w,[2,31]),{27:[1,69]},e(w,[2,13]),{26:[1,70]},{26:[2,21],28:[1,71]},e(w,[2,15]),e(w,[2,26]),e(w,[2,27]),{11:59,32:72,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},e(w,[2,33]),e(w,[2,19]),{25:73,27:ut},{26:[2,28]},{26:[2,20]}],defaultActions:{8:[2,1],10:[2,3],21:[2,2],72:[2,28],73:[2,20]},parseError:function(r,l){if(l.recoverable)this.trace(r);else{var u=new Error(r);throw u.hash=l,u}},parse:function(r){var l=this,u=[0],g=[],b=[null],a=[],F=this.table,x="",U=0,gt=0,Vt=2,xt=1,Bt=a.slice.call(arguments,1),k=Object.create(this.lexer),B={yy:{}};for(var Z in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Z)&&(B.yy[Z]=this.yy[Z]);k.setInput(r,B.yy),B.yy.lexer=k,B.yy.parser=this,typeof k.yylloc>"u"&&(k.yylloc={});var tt=k.yylloc;a.push(tt);var Wt=k.options&&k.options.ranges;typeof B.yy.parseError=="function"?this.parseError=B.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Ot(){var I;return I=g.pop()||k.lex()||xt,typeof I!="number"&&(I instanceof Array&&(g=I,I=g.pop()),I=l.symbols_[I]||I),I}for(var D,W,E,it,O={},q,M,dt,j;;){if(W=u[u.length-1],this.defaultActions[W]?E=this.defaultActions[W]:((D===null||typeof D>"u")&&(D=Ot()),E=F[W]&&F[W][D]),typeof E>"u"||!E.length||!E[0]){var et="";j=[];for(q in F[W])this.terminals_[q]&&q>Vt&&j.push("'"+this.terminals_[q]+"'");k.showPosition?et="Parse error on line "+(U+1)+`:
1
+ import{s as zt,a as Ft,v as wt,x as Nt,b as Xt,c as Yt,l as St,aH as Ht,e as $t,z as Ut,ap as ot,aJ as Ct,aL as qt,aY as jt,i as Gt}from"./mermaid.core-CG3Ib42Q.js";import{a as Qt}from"./createText-1719965b-2XqnWjQY.js";import"./index-CNo75dYr.js";import{i as Kt}from"./init-Gi6I4Gst.js";import{o as Jt}from"./ordinal-Cboi1Yqb.js";import{l as ft}from"./linear-DzGV4E9N.js";import{l as pt}from"./line-9GUsXbwv.js";import"./array-BKyUJesY.js";import"./path-CbwjOpE9.js";function Zt(e,t,i){e=+e,t=+t,i=(n=arguments.length)<2?(t=e,e=0,1):n<3?1:+i;for(var s=-1,n=Math.max(0,Math.ceil((t-e)/i))|0,o=new Array(n);++s<n;)o[s]=e+s*i;return o}function st(){var e=Jt().unknown(void 0),t=e.domain,i=e.range,s=0,n=1,o,c,f=!1,d=0,R=0,_=.5;delete e.unknown;function A(){var m=t().length,T=n<s,S=T?n:s,P=T?s:n;o=(P-S)/Math.max(1,m-d+R*2),f&&(o=Math.floor(o)),S+=(P-S-o*(m-d))*_,c=o*(1-d),f&&(S=Math.round(S),c=Math.round(c));var p=Zt(m).map(function(C){return S+o*C});return i(T?p.reverse():p)}return e.domain=function(m){return arguments.length?(t(m),A()):t()},e.range=function(m){return arguments.length?([s,n]=m,s=+s,n=+n,A()):[s,n]},e.rangeRound=function(m){return[s,n]=m,s=+s,n=+n,f=!0,A()},e.bandwidth=function(){return c},e.step=function(){return o},e.round=function(m){return arguments.length?(f=!!m,A()):f},e.padding=function(m){return arguments.length?(d=Math.min(1,R=+m),A()):d},e.paddingInner=function(m){return arguments.length?(d=Math.min(1,m),A()):d},e.paddingOuter=function(m){return arguments.length?(R=+m,A()):R},e.align=function(m){return arguments.length?(_=Math.max(0,Math.min(1,m)),A()):_},e.copy=function(){return st(t(),[s,n]).round(f).paddingInner(d).paddingOuter(R).align(_)},Kt.apply(A(),arguments)}var nt=function(){var e=function(V,r,l,u){for(l=l||{},u=V.length;u--;l[V[u]]=r);return l},t=[1,10,12,14,16,18,19,21,23],i=[2,6],s=[1,3],n=[1,5],o=[1,6],c=[1,7],f=[1,5,10,12,14,16,18,19,21,23,34,35,36],d=[1,25],R=[1,26],_=[1,28],A=[1,29],m=[1,30],T=[1,31],S=[1,32],P=[1,33],p=[1,34],C=[1,35],h=[1,36],L=[1,37],z=[1,43],lt=[1,42],ct=[1,47],$=[1,50],w=[1,10,12,14,16,18,19,21,23,34,35,36],Q=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36],v=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36,41,42,43,44,45,46,47,48,49,50],ut=[1,64],K={trace:function(){},yy:{},symbols_:{error:2,start:3,eol:4,XYCHART:5,chartConfig:6,document:7,CHART_ORIENTATION:8,statement:9,title:10,text:11,X_AXIS:12,parseXAxis:13,Y_AXIS:14,parseYAxis:15,LINE:16,plotData:17,BAR:18,acc_title:19,acc_title_value:20,acc_descr:21,acc_descr_value:22,acc_descr_multiline_value:23,SQUARE_BRACES_START:24,commaSeparatedNumbers:25,SQUARE_BRACES_END:26,NUMBER_WITH_DECIMAL:27,COMMA:28,xAxisData:29,bandData:30,ARROW_DELIMITER:31,commaSeparatedTexts:32,yAxisData:33,NEWLINE:34,SEMI:35,EOF:36,alphaNum:37,STR:38,MD_STR:39,alphaNumToken:40,AMP:41,NUM:42,ALPHA:43,PLUS:44,EQUALS:45,MULT:46,DOT:47,BRKT:48,MINUS:49,UNDERSCORE:50,$accept:0,$end:1},terminals_:{2:"error",5:"XYCHART",8:"CHART_ORIENTATION",10:"title",12:"X_AXIS",14:"Y_AXIS",16:"LINE",18:"BAR",19:"acc_title",20:"acc_title_value",21:"acc_descr",22:"acc_descr_value",23:"acc_descr_multiline_value",24:"SQUARE_BRACES_START",26:"SQUARE_BRACES_END",27:"NUMBER_WITH_DECIMAL",28:"COMMA",31:"ARROW_DELIMITER",34:"NEWLINE",35:"SEMI",36:"EOF",38:"STR",39:"MD_STR",41:"AMP",42:"NUM",43:"ALPHA",44:"PLUS",45:"EQUALS",46:"MULT",47:"DOT",48:"BRKT",49:"MINUS",50:"UNDERSCORE"},productions_:[0,[3,2],[3,3],[3,2],[3,1],[6,1],[7,0],[7,2],[9,2],[9,2],[9,2],[9,2],[9,2],[9,3],[9,2],[9,3],[9,2],[9,2],[9,1],[17,3],[25,3],[25,1],[13,1],[13,2],[13,1],[29,1],[29,3],[30,3],[32,3],[32,1],[15,1],[15,2],[15,1],[33,3],[4,1],[4,1],[4,1],[11,1],[11,1],[11,1],[37,1],[37,2],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1]],performAction:function(r,l,u,g,b,a,F){var x=a.length-1;switch(b){case 5:g.setOrientation(a[x]);break;case 9:g.setDiagramTitle(a[x].text.trim());break;case 12:g.setLineData({text:"",type:"text"},a[x]);break;case 13:g.setLineData(a[x-1],a[x]);break;case 14:g.setBarData({text:"",type:"text"},a[x]);break;case 15:g.setBarData(a[x-1],a[x]);break;case 16:this.$=a[x].trim(),g.setAccTitle(this.$);break;case 17:case 18:this.$=a[x].trim(),g.setAccDescription(this.$);break;case 19:this.$=a[x-1];break;case 20:this.$=[Number(a[x-2]),...a[x]];break;case 21:this.$=[Number(a[x])];break;case 22:g.setXAxisTitle(a[x]);break;case 23:g.setXAxisTitle(a[x-1]);break;case 24:g.setXAxisTitle({type:"text",text:""});break;case 25:g.setXAxisBand(a[x]);break;case 26:g.setXAxisRangeData(Number(a[x-2]),Number(a[x]));break;case 27:this.$=a[x-1];break;case 28:this.$=[a[x-2],...a[x]];break;case 29:this.$=[a[x]];break;case 30:g.setYAxisTitle(a[x]);break;case 31:g.setYAxisTitle(a[x-1]);break;case 32:g.setYAxisTitle({type:"text",text:""});break;case 33:g.setYAxisRangeData(Number(a[x-2]),Number(a[x]));break;case 37:this.$={text:a[x],type:"text"};break;case 38:this.$={text:a[x],type:"text"};break;case 39:this.$={text:a[x],type:"markdown"};break;case 40:this.$=a[x];break;case 41:this.$=a[x-1]+""+a[x];break}},table:[e(t,i,{3:1,4:2,7:4,5:s,34:n,35:o,36:c}),{1:[3]},e(t,i,{4:2,7:4,3:8,5:s,34:n,35:o,36:c}),e(t,i,{4:2,7:4,6:9,3:10,5:s,8:[1,11],34:n,35:o,36:c}),{1:[2,4],9:12,10:[1,13],12:[1,14],14:[1,15],16:[1,16],18:[1,17],19:[1,18],21:[1,19],23:[1,20]},e(f,[2,34]),e(f,[2,35]),e(f,[2,36]),{1:[2,1]},e(t,i,{4:2,7:4,3:21,5:s,34:n,35:o,36:c}),{1:[2,3]},e(f,[2,5]),e(t,[2,7],{4:22,34:n,35:o,36:c}),{11:23,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:39,13:38,24:z,27:lt,29:40,30:41,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:45,15:44,27:ct,33:46,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:49,17:48,24:$,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:52,17:51,24:$,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{20:[1,53]},{22:[1,54]},e(w,[2,18]),{1:[2,2]},e(w,[2,8]),e(w,[2,9]),e(Q,[2,37],{40:55,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L}),e(Q,[2,38]),e(Q,[2,39]),e(v,[2,40]),e(v,[2,42]),e(v,[2,43]),e(v,[2,44]),e(v,[2,45]),e(v,[2,46]),e(v,[2,47]),e(v,[2,48]),e(v,[2,49]),e(v,[2,50]),e(v,[2,51]),e(w,[2,10]),e(w,[2,22],{30:41,29:56,24:z,27:lt}),e(w,[2,24]),e(w,[2,25]),{31:[1,57]},{11:59,32:58,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},e(w,[2,11]),e(w,[2,30],{33:60,27:ct}),e(w,[2,32]),{31:[1,61]},e(w,[2,12]),{17:62,24:$},{25:63,27:ut},e(w,[2,14]),{17:65,24:$},e(w,[2,16]),e(w,[2,17]),e(v,[2,41]),e(w,[2,23]),{27:[1,66]},{26:[1,67]},{26:[2,29],28:[1,68]},e(w,[2,31]),{27:[1,69]},e(w,[2,13]),{26:[1,70]},{26:[2,21],28:[1,71]},e(w,[2,15]),e(w,[2,26]),e(w,[2,27]),{11:59,32:72,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},e(w,[2,33]),e(w,[2,19]),{25:73,27:ut},{26:[2,28]},{26:[2,20]}],defaultActions:{8:[2,1],10:[2,3],21:[2,2],72:[2,28],73:[2,20]},parseError:function(r,l){if(l.recoverable)this.trace(r);else{var u=new Error(r);throw u.hash=l,u}},parse:function(r){var l=this,u=[0],g=[],b=[null],a=[],F=this.table,x="",U=0,gt=0,Vt=2,xt=1,Bt=a.slice.call(arguments,1),k=Object.create(this.lexer),B={yy:{}};for(var Z in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Z)&&(B.yy[Z]=this.yy[Z]);k.setInput(r,B.yy),B.yy.lexer=k,B.yy.parser=this,typeof k.yylloc>"u"&&(k.yylloc={});var tt=k.yylloc;a.push(tt);var Wt=k.options&&k.options.ranges;typeof B.yy.parseError=="function"?this.parseError=B.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Ot(){var I;return I=g.pop()||k.lex()||xt,typeof I!="number"&&(I instanceof Array&&(g=I,I=g.pop()),I=l.symbols_[I]||I),I}for(var D,W,E,it,O={},q,M,dt,j;;){if(W=u[u.length-1],this.defaultActions[W]?E=this.defaultActions[W]:((D===null||typeof D>"u")&&(D=Ot()),E=F[W]&&F[W][D]),typeof E>"u"||!E.length||!E[0]){var et="";j=[];for(q in F[W])this.terminals_[q]&&q>Vt&&j.push("'"+this.terminals_[q]+"'");k.showPosition?et="Parse error on line "+(U+1)+`:
2
2
  `+k.showPosition()+`
3
3
  Expecting `+j.join(", ")+", got '"+(this.terminals_[D]||D)+"'":et="Parse error on line "+(U+1)+": Unexpected "+(D==xt?"end of input":"'"+(this.terminals_[D]||D)+"'"),this.parseError(et,{text:k.match,token:this.terminals_[D]||D,line:k.yylineno,loc:tt,expected:j})}if(E[0]instanceof Array&&E.length>1)throw new Error("Parse Error: multiple actions possible at state: "+W+", token: "+D);switch(E[0]){case 1:u.push(D),b.push(k.yytext),a.push(k.yylloc),u.push(E[1]),D=null,gt=k.yyleng,x=k.yytext,U=k.yylineno,tt=k.yylloc;break;case 2:if(M=this.productions_[E[1]][1],O.$=b[b.length-M],O._$={first_line:a[a.length-(M||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(M||1)].first_column,last_column:a[a.length-1].last_column},Wt&&(O._$.range=[a[a.length-(M||1)].range[0],a[a.length-1].range[1]]),it=this.performAction.apply(O,[x,gt,U,B.yy,E[1],b,a].concat(Bt)),typeof it<"u")return it;M&&(u=u.slice(0,-1*M*2),b=b.slice(0,-1*M),a=a.slice(0,-1*M)),u.push(this.productions_[E[1]][0]),b.push(O.$),a.push(O._$),dt=F[u[u.length-2]][u[u.length-1]],u.push(dt);break;case 3:return!0}}return!0}},It=function(){var V={EOF:1,parseError:function(l,u){if(this.yy.parser)this.yy.parser.parseError(l,u);else throw new Error(l)},setInput:function(r,l){return this.yy=l||this.yy||{},this._input=r,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var r=this._input[0];this.yytext+=r,this.yyleng++,this.offset++,this.match+=r,this.matched+=r;var l=r.match(/(?:\r\n?|\n).*/g);return l?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),r},unput:function(r){var l=r.length,u=r.split(/(?:\r\n?|\n)/g);this._input=r+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-l),this.offset-=l;var g=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),u.length-1&&(this.yylineno-=u.length-1);var b=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:u?(u.length===g.length?this.yylloc.first_column:0)+g[g.length-u.length].length-u[0].length:this.yylloc.first_column-l},this.options.ranges&&(this.yylloc.range=[b[0],b[0]+this.yyleng-l]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
4
4
  `+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},less:function(r){this.unput(this.match.slice(r))},pastInput:function(){var r=this.matched.substr(0,this.matched.length-this.match.length);return(r.length>20?"...":"")+r.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var r=this.match;return r.length<20&&(r+=this._input.substr(0,20-r.length)),(r.substr(0,20)+(r.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var r=this.pastInput(),l=new Array(r.length+1).join("-");return r+this.upcomingInput()+`
package/dist/index.html CHANGED
@@ -19,8 +19,8 @@
19
19
  type="text/css"
20
20
  href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css"
21
21
  />
22
- <script type="module" crossorigin src="/assets/index-CNMzWvKV.js"></script>
23
- <link rel="stylesheet" crossorigin href="/assets/index-PEmISxiy.css">
22
+ <script type="module" crossorigin src="/assets/index-CNo75dYr.js"></script>
23
+ <link rel="stylesheet" crossorigin href="/assets/index-B0qfCb1G.css">
24
24
  </head>
25
25
  <body>
26
26
  <div id="root"></div>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vibe-forge/client",
3
3
  "type": "module",
4
- "version": "0.2.0-alpha.8",
4
+ "version": "0.3.0",
5
5
  "imports": {
6
6
  "#~/*": [
7
7
  "./src/*",
@@ -33,8 +33,8 @@
33
33
  "typescript": "^5.6.3",
34
34
  "vite": "^5.4.8",
35
35
  "vitest": "^3.2.4",
36
- "@vibe-forge/core": "0.2.0-alpha.8",
37
- "@vibe-forge/register": "^0.2.0-alpha.8"
36
+ "@vibe-forge/core": "0.3.0",
37
+ "@vibe-forge/register": "^0.3.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/react": "^18.3.12",
package/src/api.ts CHANGED
@@ -21,6 +21,14 @@ export interface EntitySummary {
21
21
  rules: string[]
22
22
  }
23
23
 
24
+ export interface RuleSummary {
25
+ id: string
26
+ name: string
27
+ description: string
28
+ always: boolean
29
+ globs?: string[]
30
+ }
31
+
24
32
  export interface SpecDetail extends SpecSummary {
25
33
  body: string
26
34
  }
@@ -29,6 +37,10 @@ export interface EntityDetail extends EntitySummary {
29
37
  body: string
30
38
  }
31
39
 
40
+ export interface RuleDetail extends RuleSummary {
41
+ body: string
42
+ }
43
+
32
44
  export interface AutomationTrigger {
33
45
  id: string
34
46
  type: 'interval' | 'webhook' | 'cron'
@@ -96,11 +108,15 @@ export async function listSessions(filter: 'active' | 'archived' | 'all' = 'acti
96
108
  return res.json() as Promise<{ sessions: Session[] }>
97
109
  }
98
110
 
99
- export async function createSession(title?: string, initialMessage?: string): Promise<{ session: Session }> {
111
+ export async function createSession(
112
+ title?: string,
113
+ initialMessage?: string,
114
+ model?: string
115
+ ): Promise<{ session: Session }> {
100
116
  const res = await fetch(`${SERVER_URL}/api/sessions`, {
101
117
  method: 'POST',
102
118
  headers: { 'Content-Type': 'application/json' },
103
- body: JSON.stringify({ title, initialMessage })
119
+ body: JSON.stringify({ title, initialMessage, model })
104
120
  })
105
121
  return res.json() as Promise<{ session: Session }>
106
122
  }
@@ -115,6 +131,11 @@ export async function listEntities(): Promise<{ entities: EntitySummary[] }> {
115
131
  return res.json() as Promise<{ entities: EntitySummary[] }>
116
132
  }
117
133
 
134
+ export async function listRules(): Promise<{ rules: RuleSummary[] }> {
135
+ const res = await fetch(`${SERVER_URL}/api/ai/rules`)
136
+ return res.json() as Promise<{ rules: RuleSummary[] }>
137
+ }
138
+
118
139
  export async function getSpecDetail(path: string): Promise<{ spec: SpecDetail }> {
119
140
  const url = new URL(`${SERVER_URL}/api/ai/specs/detail`)
120
141
  url.searchParams.set('path', path)
@@ -129,6 +150,13 @@ export async function getEntityDetail(path: string): Promise<{ entity: EntityDet
129
150
  return res.json() as Promise<{ entity: EntityDetail }>
130
151
  }
131
152
 
153
+ export async function getRuleDetail(path: string): Promise<{ rule: RuleDetail }> {
154
+ const url = new URL(`${SERVER_URL}/api/ai/rules/detail`)
155
+ url.searchParams.set('path', path)
156
+ const res = await fetch(url.toString())
157
+ return res.json() as Promise<{ rule: RuleDetail }>
158
+ }
159
+
132
160
  export async function getConfig(): Promise<ConfigResponse> {
133
161
  const res = await fetch(`${SERVER_URL}/api/config`)
134
162
  return res.json() as Promise<ConfigResponse>
@@ -9,6 +9,7 @@ import type { AboutInfo, ConfigResponse, ConfigSource } from '@vibe-forge/core'
9
9
 
10
10
  import { getConfig, updateConfig } from '../api'
11
11
  import { AboutSection, ConfigSectionPanel, ConfigSourceSwitch, DisplayValue } from './config'
12
+ import { AppSettingsPanel } from './config/AppSettingsPanel'
12
13
  import { cloneValue, getValueByPath, isEmptyValue } from './config/configUtils'
13
14
 
14
15
  export function ConfigView() {
@@ -75,6 +76,7 @@ export function ConfigView() {
75
76
  { key: 'mcp', icon: 'account_tree', label: t('config.sections.mcp'), value: currentSource?.mcp },
76
77
  { key: 'shortcuts', icon: 'keyboard', label: t('config.sections.shortcuts'), value: currentSource?.shortcuts },
77
78
  { key: 'group-app', type: 'group', label: t('config.groups.app') },
79
+ { key: 'appearance', icon: 'tune', label: t('config.sections.appearance') },
78
80
  { key: 'experiments', icon: 'science', label: t('config.sections.experiments'), value: data?.meta?.experiments },
79
81
  { key: 'about', icon: 'info', label: t('config.sections.about'), value: data?.meta?.about }
80
82
  ], [currentSource, data?.meta?.about, data?.meta?.experiments, t])
@@ -220,7 +222,10 @@ export function ConfigView() {
220
222
  {tab.key === 'about' && (
221
223
  <AboutSection value={tab.value as AboutInfo | undefined} />
222
224
  )}
223
- {tab.key !== 'about' && !configTabKeys.has(tab.key) && (
225
+ {tab.key === 'appearance' && (
226
+ <AppSettingsPanel t={t} />
227
+ )}
228
+ {tab.key !== 'about' && tab.key !== 'appearance' && !configTabKeys.has(tab.key) && (
224
229
  <DisplayValue value={tab.value} sectionKey={tab.key} t={t} />
225
230
  )}
226
231
  {configTabKeys.has(tab.key) && (
@@ -15,19 +15,47 @@
15
15
  }
16
16
 
17
17
  .new-session-guide__announcements-header {
18
- display: inline-flex;
18
+ display: flex;
19
19
  align-items: center;
20
- gap: 8px;
20
+ justify-content: space-between;
21
+ gap: 12px;
21
22
  font-size: 13px;
22
23
  font-weight: 600;
23
24
  color: var(--text-color);
24
25
  }
25
26
 
27
+ .new-session-guide__announcements-title {
28
+ display: inline-flex;
29
+ align-items: center;
30
+ gap: 8px;
31
+ min-width: 0;
32
+ }
33
+
26
34
  .new-session-guide__announcements-icon {
27
35
  font-size: 18px;
28
36
  color: var(--sub-text-color);
29
37
  }
30
38
 
39
+ .new-session-guide__announcements-close {
40
+ border: none;
41
+ background: transparent;
42
+ padding: 0;
43
+ color: var(--sub-text-color);
44
+ cursor: pointer;
45
+ line-height: 1;
46
+ display: inline-flex;
47
+ align-items: center;
48
+ justify-content: center;
49
+ }
50
+
51
+ .new-session-guide__announcements-close:hover {
52
+ color: var(--text-color);
53
+ }
54
+
55
+ .new-session-guide__announcements-close .material-symbols-rounded {
56
+ font-size: 18px;
57
+ }
58
+
31
59
  .new-session-guide__announcements-list {
32
60
  display: flex;
33
61
  flex-direction: column;
@@ -53,10 +81,6 @@
53
81
  display: flex;
54
82
  flex-direction: column;
55
83
  gap: 12px;
56
- border: 1px solid var(--border-color);
57
- border-radius: 12px;
58
- padding: 16px;
59
- background: var(--bg-color);
60
84
  }
61
85
 
62
86
  .new-session-guide__header {
@@ -92,7 +116,8 @@
92
116
  display: flex;
93
117
  flex-direction: column;
94
118
  gap: 12px;
95
- min-height: 160px;
119
+ height: 160px;
120
+ overflow: scroll;
96
121
  }
97
122
 
98
123
  .new-session-guide__list {
@@ -105,16 +130,13 @@
105
130
  display: flex;
106
131
  flex-direction: column;
107
132
  gap: 4px;
108
- padding: 10px 12px;
109
- border-radius: 10px;
110
- background: var(--tag-bg);
111
133
  }
112
134
 
113
135
  .new-session-guide__item-title {
114
136
  display: inline-flex;
115
137
  align-items: center;
116
138
  gap: 6px;
117
- font-size: 13px;
139
+ font-size: 12px;
118
140
  font-weight: 600;
119
141
  color: var(--text-color);
120
142
  }
@@ -126,13 +148,13 @@
126
148
 
127
149
  .new-session-guide__item-desc {
128
150
  font-size: 12px;
129
- color: var(--sub-text-color);
151
+ color: var(--placeholder-color);
130
152
  line-height: 1.4;
131
153
  }
132
154
 
133
155
  .new-session-guide__meta {
134
156
  font-size: 11px;
135
- color: var(--sub-text-color);
157
+ color: var(--placeholder-color);
136
158
  }
137
159
 
138
160
  .new-session-guide__empty {
@@ -1,15 +1,17 @@
1
1
  import './NewSessionGuide.scss'
2
2
 
3
3
  import { App, Button } from 'antd'
4
- import React from 'react'
4
+ import { useAtom } from 'jotai'
5
5
  import { useTranslation } from 'react-i18next'
6
6
  import useSWR from 'swr'
7
7
 
8
8
  import type { EntitySummary, SpecSummary } from '#~/api.js'
9
+ import { showAnnouncementsAtom } from '#~/store/index.js'
9
10
 
10
11
  export function NewSessionGuide() {
11
12
  const { t } = useTranslation()
12
13
  const { message } = App.useApp()
14
+ const [showAnnouncements, setShowAnnouncements] = useAtom(showAnnouncementsAtom)
13
15
 
14
16
  const { data: specsRes } = useSWR<{ specs: SpecSummary[] }>('/api/ai/specs')
15
17
  const { data: entitiesRes } = useSWR<{ entities: EntitySummary[] }>('/api/ai/entities')
@@ -26,6 +28,7 @@ export function NewSessionGuide() {
26
28
  )
27
29
 
28
30
  const specs = specsRes?.specs ?? []
31
+ const alwaysSpecs = specs.filter(spec => spec.always)
29
32
  const entities = entitiesRes?.entities ?? []
30
33
  const isSpecsReady = specsRes != null
31
34
  const isEntitiesReady = entitiesRes != null
@@ -47,11 +50,20 @@ export function NewSessionGuide() {
47
50
 
48
51
  return (
49
52
  <div className='new-session-guide'>
50
- {announcements.length > 0 && (
53
+ {showAnnouncements && announcements.length > 0 && (
51
54
  <div className='new-session-guide__announcements'>
52
55
  <div className='new-session-guide__announcements-header'>
53
- <span className='material-symbols-rounded new-session-guide__announcements-icon'>campaign</span>
54
- <span>{t('chat.newSessionGuide.announcements.title')}</span>
56
+ <div className='new-session-guide__announcements-title'>
57
+ <span className='material-symbols-rounded new-session-guide__announcements-icon'>campaign</span>
58
+ <span>{t('chat.newSessionGuide.announcements.title')}</span>
59
+ </div>
60
+ <button
61
+ type='button'
62
+ className='new-session-guide__announcements-close'
63
+ onClick={() => setShowAnnouncements(false)}
64
+ >
65
+ <span className='material-symbols-rounded'>close</span>
66
+ </button>
55
67
  </div>
56
68
  <div className='new-session-guide__announcements-list'>
57
69
  {announcements.map((item, index) => (
@@ -69,18 +81,17 @@ export function NewSessionGuide() {
69
81
  <span className='material-symbols-rounded new-session-guide__title-icon'>account_tree</span>
70
82
  <span>{t('chat.newSessionGuide.specs.title')}</span>
71
83
  </div>
72
- <div className='new-session-guide__count'>{specs.length}</div>
84
+ <div className='new-session-guide__count'>{alwaysSpecs.length}</div>
73
85
  </div>
74
86
  <div className='new-session-guide__body'>
75
87
  {!isSpecsReady && (
76
88
  <div className='new-session-guide__loading'>{t('chat.newSessionGuide.loading')}</div>
77
89
  )}
78
- {isSpecsReady && specs.length > 0 && (
90
+ {isSpecsReady && alwaysSpecs.length > 0 && (
79
91
  <div className='new-session-guide__list'>
80
- {specs.map((spec) => (
92
+ {alwaysSpecs.map((spec) => (
81
93
  <div key={spec.id} className='new-session-guide__item'>
82
94
  <div className='new-session-guide__item-title'>
83
- <span className='material-symbols-rounded new-session-guide__item-icon'>route</span>
84
95
  <span>{spec.name}</span>
85
96
  </div>
86
97
  <div className='new-session-guide__item-desc'>{spec.description}</div>
@@ -93,7 +104,7 @@ export function NewSessionGuide() {
93
104
  ))}
94
105
  </div>
95
106
  )}
96
- {isSpecsReady && specs.length === 0 && (
107
+ {isSpecsReady && alwaysSpecs.length === 0 && (
97
108
  <div className='new-session-guide__empty'>
98
109
  <div className='new-session-guide__empty-desc'>{t('chat.newSessionGuide.specs.empty')}</div>
99
110
  <Button type='primary' size='small' onClick={handleCreateSpec}>
@@ -121,7 +132,6 @@ export function NewSessionGuide() {
121
132
  {entities.map((entity) => (
122
133
  <div key={entity.id} className='new-session-guide__item'>
123
134
  <div className='new-session-guide__item-title'>
124
- <span className='material-symbols-rounded new-session-guide__item-icon'>person</span>
125
135
  <span>{entity.name}</span>
126
136
  </div>
127
137
  <div className='new-session-guide__item-desc'>{entity.description}</div>
@@ -18,7 +18,14 @@ interface ModelSelectGroup {
18
18
 
19
19
  export function useChatModels() {
20
20
  const { t } = useTranslation()
21
- const [selectedModel, setSelectedModel] = useState<string | undefined>(undefined)
21
+ const [selectedModel, setSelectedModel] = useState<string | undefined>(() => {
22
+ try {
23
+ const raw = localStorage.getItem('vf_chat_selected_model')
24
+ return raw == null || raw.trim() === '' ? undefined : raw
25
+ } catch {
26
+ return undefined
27
+ }
28
+ })
22
29
  const { data: configRes } = useSWR<ConfigResponse>('/api/config', getConfig)
23
30
 
24
31
  const mergedModelServices = useMemo(() => {
@@ -77,6 +84,17 @@ export function useChatModels() {
77
84
  })
78
85
  }, [availableModelSet, hasAvailableModels, resolvedDefaultModel])
79
86
 
87
+ useEffect(() => {
88
+ try {
89
+ if (selectedModel == null || selectedModel.trim() === '') {
90
+ localStorage.removeItem('vf_chat_selected_model')
91
+ } else {
92
+ localStorage.setItem('vf_chat_selected_model', selectedModel)
93
+ }
94
+ } catch {
95
+ }
96
+ }, [selectedModel])
97
+
80
98
  const modelOptions = useMemo<ModelSelectGroup[]>(() => {
81
99
  const buildOption = (params: {
82
100
  value: string
@@ -302,7 +302,7 @@ export function useChatSession({
302
302
  if (!session?.id) {
303
303
  setIsCreating(true)
304
304
  try {
305
- const { session: newSession } = await createSession(undefined, text.trim())
305
+ const { session: newSession } = await createSession(undefined, text.trim(), selectedModel)
306
306
 
307
307
  await mutate('/api/sessions', (prev: { sessions: Session[] } | undefined) => {
308
308
  if (!prev?.sessions) return { sessions: [newSession] }
@@ -0,0 +1,33 @@
1
+ import '../ConfigView.scss'
2
+
3
+ import { Switch } from 'antd'
4
+ import { useAtom } from 'jotai'
5
+
6
+ import { showAnnouncementsAtom } from '#~/store/index.js'
7
+
8
+ import { FieldRow } from './ConfigFieldRow'
9
+ import type { TranslationFn } from './configUtils'
10
+
11
+ export function AppSettingsPanel({ t }: { t: TranslationFn }) {
12
+ const [showAnnouncements, setShowAnnouncements] = useAtom(showAnnouncementsAtom)
13
+
14
+ return (
15
+ <div className='config-view__editor-wrap'>
16
+ <div className='config-view__section-header'>
17
+ <div className='config-view__section-title'>
18
+ <span className='material-symbols-rounded config-view__section-icon'>tune</span>
19
+ <span>{t('config.sections.appearance')}</span>
20
+ </div>
21
+ </div>
22
+ <div className='config-view__card'>
23
+ <FieldRow
24
+ title={t('config.appSettings.announcements.label')}
25
+ description={t('config.appSettings.announcements.desc')}
26
+ icon='campaign'
27
+ >
28
+ <Switch checked={showAnnouncements} onChange={setShowAnnouncements} />
29
+ </FieldRow>
30
+ </div>
31
+ </div>
32
+ )
33
+ }
@@ -5,7 +5,8 @@ import React from 'react'
5
5
  import { useTranslation } from 'react-i18next'
6
6
  import useSWR from 'swr'
7
7
 
8
- import type { EntitySummary, SpecSummary } from '#~/api.js'
8
+ import type { EntitySummary, RuleSummary, SpecSummary } from '#~/api.js'
9
+ import { useQueryParams } from '#~/hooks/useQueryParams.js'
9
10
  import { EntitiesTab } from './components/EntitiesTab.js'
10
11
  import { FlowsTab } from './components/FlowsTab.js'
11
12
  import { KnowledgeBaseHeader } from './components/KnowledgeBaseHeader.js'
@@ -13,6 +14,10 @@ import { RulesTab } from './components/RulesTab.js'
13
14
  import { SkillsTab } from './components/SkillsTab.js'
14
15
  import { TabLabel } from './components/TabLabel.js'
15
16
 
17
+ interface KnowledgeQueryParams extends Record<string, string> {
18
+ kbTab: string
19
+ }
20
+
16
21
  export function KnowledgeBaseView() {
17
22
  const { t } = useTranslation()
18
23
  const { message } = App.useApp()
@@ -26,14 +31,28 @@ export function KnowledgeBaseView() {
26
31
  isLoading: isEntitiesLoading,
27
32
  mutate: mutateEntities
28
33
  } = useSWR<{ entities: EntitySummary[] }>('/api/ai/entities')
34
+ const {
35
+ data: rulesRes,
36
+ isLoading: isRulesLoading,
37
+ mutate: mutateRules
38
+ } = useSWR<{ rules: RuleSummary[] }>('/api/ai/rules')
29
39
 
30
40
  const specs = specsRes?.specs ?? []
31
41
  const entities = entitiesRes?.entities ?? []
42
+ const rules = rulesRes?.rules ?? []
32
43
 
33
44
  const [specQuery, setSpecQuery] = React.useState('')
34
45
  const [specTagFilter, setSpecTagFilter] = React.useState<string[]>([])
35
46
  const [entityQuery, setEntityQuery] = React.useState('')
36
47
  const [entityTagFilter, setEntityTagFilter] = React.useState<string[]>([])
48
+ const [ruleQuery, setRuleQuery] = React.useState('')
49
+
50
+ const { values, update } = useQueryParams<KnowledgeQueryParams>({
51
+ keys: ['kbTab'],
52
+ defaults: {
53
+ kbTab: 'skills'
54
+ }
55
+ })
37
56
 
38
57
  const specTagOptions = React.useMemo(() => {
39
58
  const tags = new Set<string>()
@@ -81,8 +100,18 @@ export function KnowledgeBaseView() {
81
100
  })
82
101
  }, [entityQuery, entityTagFilter, entities])
83
102
 
103
+ const filteredRules = React.useMemo(() => {
104
+ const query = ruleQuery.trim().toLowerCase()
105
+ return rules.filter(rule => {
106
+ if (query === '') return true
107
+ const globText = (rule.globs ?? []).join(' ')
108
+ const haystack = `${rule.name} ${rule.description} ${globText}`.toLowerCase()
109
+ return haystack.includes(query)
110
+ })
111
+ }, [ruleQuery, rules])
112
+
84
113
  const handleRefresh = async () => {
85
- await Promise.all([mutateSpecs(), mutateEntities()])
114
+ await Promise.all([mutateSpecs(), mutateEntities(), mutateRules()])
86
115
  void message.success(t('knowledge.actions.refreshed'))
87
116
  }
88
117
 
@@ -170,6 +199,11 @@ export function KnowledgeBaseView() {
170
199
  label: <TabLabel icon='gavel' label={t('knowledge.tabs.rules')} />,
171
200
  children: (
172
201
  <RulesTab
202
+ rules={rules}
203
+ filteredRules={filteredRules}
204
+ isLoading={isRulesLoading}
205
+ query={ruleQuery}
206
+ onQueryChange={setRuleQuery}
173
207
  onCreate={handleCreateRule}
174
208
  onImport={handleImportRule}
175
209
  />
@@ -177,10 +211,24 @@ export function KnowledgeBaseView() {
177
211
  }
178
212
  ]
179
213
 
214
+ const tabKeys = React.useMemo(() => tabs.map(tab => tab.key), [tabs])
215
+ const activeTab = tabKeys.includes(values.kbTab) ? values.kbTab : tabKeys[0]
216
+
217
+ React.useEffect(() => {
218
+ if (values.kbTab !== activeTab) {
219
+ update({ kbTab: activeTab })
220
+ }
221
+ }, [activeTab, update, values.kbTab])
222
+
180
223
  return (
181
224
  <div className='knowledge-base-view'>
182
225
  <KnowledgeBaseHeader onRefresh={handleRefresh} />
183
- <Tabs className='knowledge-base-view__tabs' items={tabs} />
226
+ <Tabs
227
+ className='knowledge-base-view__tabs'
228
+ items={tabs}
229
+ activeKey={activeTab}
230
+ onChange={(key) => update({ kbTab: key })}
231
+ />
184
232
  </div>
185
233
  )
186
234
  }
@@ -0,0 +1,79 @@
1
+ import { Button, Empty, Tag, Tooltip } from 'antd'
2
+ import React from 'react'
3
+ import { useTranslation } from 'react-i18next'
4
+ import useSWR from 'swr'
5
+
6
+ import type { RuleDetail, RuleSummary } from '#~/api.js'
7
+ import { getRuleDetail } from '#~/api.js'
8
+ import { MarkdownContent } from '#~/components/chat/MarkdownContent'
9
+ import { LoadingState } from './LoadingState'
10
+
11
+ type RuleItemProps = {
12
+ rule: RuleSummary
13
+ }
14
+
15
+ export function RuleItem({ rule }: RuleItemProps) {
16
+ const { t } = useTranslation()
17
+ const [expanded, setExpanded] = React.useState(false)
18
+ const { data, isLoading } = useSWR<{ rule: RuleDetail }>(
19
+ expanded ? ['rule-detail', rule.id] : null,
20
+ () => getRuleDetail(rule.id)
21
+ )
22
+ const detail = data?.rule
23
+ const body = detail?.body ?? ''
24
+ const globList = rule.globs ?? []
25
+
26
+ return (
27
+ <div className='knowledge-base-view__item'>
28
+ <div className='knowledge-base-view__item-row'>
29
+ <div className='knowledge-base-view__item-main'>
30
+ <div className='knowledge-base-view__item-title'>
31
+ <span className='material-symbols-rounded knowledge-base-view__item-icon'>gavel</span>
32
+ <span>{rule.name}</span>
33
+ </div>
34
+ <div className='knowledge-base-view__item-desc'>{rule.description}</div>
35
+ {globList.length > 0 && (
36
+ <div className='knowledge-base-view__tag-list'>
37
+ {globList.map(glob => (
38
+ <Tag key={glob} className='knowledge-base-view__tag'>
39
+ <span className='material-symbols-rounded knowledge-base-view__tag-icon'>folder</span>
40
+ <span>{glob}</span>
41
+ </Tag>
42
+ ))}
43
+ </div>
44
+ )}
45
+ </div>
46
+ <div className='knowledge-base-view__item-meta'>
47
+ {rule.always && (
48
+ <Tag color='blue'>{t('knowledge.meta.always')}</Tag>
49
+ )}
50
+ <Tooltip title={expanded ? t('knowledge.actions.collapse') : t('knowledge.actions.expand')}>
51
+ <Button
52
+ type='text'
53
+ className='knowledge-base-view__icon-button'
54
+ onClick={() => setExpanded(prev => !prev)}
55
+ icon={
56
+ <span className='material-symbols-rounded'>
57
+ {expanded ? 'expand_less' : 'expand_more'}
58
+ </span>
59
+ }
60
+ />
61
+ </Tooltip>
62
+ </div>
63
+ </div>
64
+ {expanded && (
65
+ <div className='knowledge-base-view__detail'>
66
+ {isLoading && <LoadingState />}
67
+ {!isLoading && body.trim() === '' && (
68
+ <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t('knowledge.rules.empty')} />
69
+ )}
70
+ {!isLoading && body.trim() !== '' && (
71
+ <div className='knowledge-base-view__markdown'>
72
+ <MarkdownContent content={body} />
73
+ </div>
74
+ )}
75
+ </div>
76
+ )}
77
+ </div>
78
+ )
79
+ }
@@ -0,0 +1,5 @@
1
+ .knowledge-base-view__rule-list {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: 12px;
5
+ }