@vibe-forge/client 0.5.0 → 0.6.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 (134) hide show
  1. package/AGENTS.md +37 -0
  2. package/dist/assets/{arc-C4ymrcSQ.js → arc-CMAHd5G3.js} +1 -1
  3. package/dist/assets/{blockDiagram-c4efeb88-CeB7-kgP.js → blockDiagram-c4efeb88-DKww-VCP.js} +1 -1
  4. package/dist/assets/{c4Diagram-c83219d4-C935Im8S.js → c4Diagram-c83219d4-DKrjVHyY.js} +1 -1
  5. package/dist/assets/channel-Bi4g8rj9.js +1 -0
  6. package/dist/assets/{classDiagram-beda092f-B9IV13KI.js → classDiagram-beda092f-BXx5rdo3.js} +1 -1
  7. package/dist/assets/{classDiagram-v2-2358418a-CXF_K4fE.js → classDiagram-v2-2358418a-CnR3WLsr.js} +1 -1
  8. package/dist/assets/clone-DPrpP2ky.js +1 -0
  9. package/dist/assets/{createText-1719965b-DwX8iC5F.js → createText-1719965b-CmOsl1W7.js} +1 -1
  10. package/dist/assets/{edges-96097737-9P1uH1RE.js → edges-96097737-CQeQgpjD.js} +1 -1
  11. package/dist/assets/{erDiagram-0228fc6a-ixeGTFvg.js → erDiagram-0228fc6a-ZUNB-ucF.js} +1 -1
  12. package/dist/assets/{flowDb-c6c81e3f-G1gSTTBI.js → flowDb-c6c81e3f-DuuKeSLX.js} +1 -1
  13. package/dist/assets/{flowDiagram-50d868cf-CzrG99nD.js → flowDiagram-50d868cf-Bc6n85yR.js} +1 -1
  14. package/dist/assets/flowDiagram-v2-4f6560a1-BZqaeqoh.js +1 -0
  15. package/dist/assets/{flowchart-elk-definition-6af322e1-sFCoysWa.js → flowchart-elk-definition-6af322e1-cAG5afW9.js} +1 -1
  16. package/dist/assets/{ganttDiagram-a2739b55-Ccsk_Lru.js → ganttDiagram-a2739b55-Dp6xhY5I.js} +1 -1
  17. package/dist/assets/{gitGraphDiagram-82fe8481-CwathJ6H.js → gitGraphDiagram-82fe8481-MlIIRBdG.js} +1 -1
  18. package/dist/assets/{graph-DRCU-8Rz.js → graph-D7Es8jZ-.js} +1 -1
  19. package/dist/assets/{index-5325376f-Bq-fg2i_.js → index-5325376f-DC18ottv.js} +1 -1
  20. package/dist/assets/index-D37AbgPQ.js +545 -0
  21. package/dist/assets/{index-CHMuZ5-1.css → index-fcJ9v94I.css} +1 -1
  22. package/dist/assets/{infoDiagram-8eee0895-JBcUkJ6T.js → infoDiagram-8eee0895-CXk21kFp.js} +1 -1
  23. package/dist/assets/{journeyDiagram-c64418c1-DsdQU-R8.js → journeyDiagram-c64418c1-899BKBHL.js} +1 -1
  24. package/dist/assets/{layout-s0slG1OL.js → layout-DLaxdy48.js} +1 -1
  25. package/dist/assets/{line-CymFqgW6.js → line-_lw5YbRM.js} +1 -1
  26. package/dist/assets/{linear-lDQVZ6aQ.js → linear-D5iu84ui.js} +1 -1
  27. package/dist/assets/{mermaid.core-Cmlqga_E.js → mermaid.core-C6sW3GFM.js} +4 -4
  28. package/dist/assets/{mindmap-definition-8da855dc-CqqTDJn_.js → mindmap-definition-8da855dc-BS9Xy9KN.js} +1 -1
  29. package/dist/assets/{pieDiagram-a8764435-BL2Ajx7Z.js → pieDiagram-a8764435-DZt9cEgs.js} +1 -1
  30. package/dist/assets/{quadrantDiagram-1e28029f-ClL_3ASt.js → quadrantDiagram-1e28029f-BTIeHOgn.js} +1 -1
  31. package/dist/assets/{requirementDiagram-08caed73-CB1RgE3K.js → requirementDiagram-08caed73-BHJAKD2g.js} +1 -1
  32. package/dist/assets/{sankeyDiagram-a04cb91d-tgleEYiD.js → sankeyDiagram-a04cb91d-DnAkVOK8.js} +1 -1
  33. package/dist/assets/{sequenceDiagram-c5b8d532-DlatQT5R.js → sequenceDiagram-c5b8d532-92tE3oFv.js} +1 -1
  34. package/dist/assets/{stateDiagram-1ecb1508-B--MLqRs.js → stateDiagram-1ecb1508-DG0ObiMg.js} +1 -1
  35. package/dist/assets/{stateDiagram-v2-c2b004d7-CRMZ6Dpx.js → stateDiagram-v2-c2b004d7-BKoJx2ci.js} +1 -1
  36. package/dist/assets/{styles-b4e223ce-CPiYHfUz.js → styles-b4e223ce-Ba6G4ri9.js} +1 -1
  37. package/dist/assets/{styles-ca3715f6-B9UKPAzX.js → styles-ca3715f6-Bn6RIIVW.js} +1 -1
  38. package/dist/assets/{styles-d45a18b0-BC1Ak1So.js → styles-d45a18b0-_dELBUI6.js} +1 -1
  39. package/dist/assets/{svgDrawCommon-b86b1483-DV8R0g-n.js → svgDrawCommon-b86b1483-CRK-ZoIs.js} +1 -1
  40. package/dist/assets/{timeline-definition-faaaa080-CiqGS5DC.js → timeline-definition-faaaa080-DvQ_RA_i.js} +1 -1
  41. package/dist/assets/{xychartDiagram-f5964ef8-h6VSD3GE.js → xychartDiagram-f5964ef8-CJxeDLfg.js} +1 -1
  42. package/dist/index.html +2 -2
  43. package/package.json +10 -8
  44. package/src/App.tsx +20 -168
  45. package/src/api/base.ts +116 -7
  46. package/src/api.ts +3 -1
  47. package/src/components/ArchiveView.tsx +5 -5
  48. package/src/components/ConfigView.tsx +3 -3
  49. package/src/components/{AutomationView → automation-view}/index.tsx +10 -9
  50. package/src/components/{BenchmarkView → benchmark-view}/index.tsx +5 -4
  51. package/src/components/chat/ChatHeader.tsx +6 -6
  52. package/src/components/chat/ChatHistoryView.tsx +64 -16
  53. package/src/components/chat/ChatTimelineView.tsx +3 -3
  54. package/src/components/chat/CurrentTodoList.scss +56 -27
  55. package/src/components/chat/{Sender → sender}/Sender.scss +201 -71
  56. package/src/components/chat/{Sender → sender}/Sender.tsx +104 -42
  57. package/src/components/chat/tools/core/ToolGroup.tsx +1 -1
  58. package/src/components/config/ConfigSectionForm.tsx +1 -1
  59. package/src/components/layout/AppShell.scss +19 -0
  60. package/src/components/layout/AppShell.tsx +45 -0
  61. package/src/hooks/chat/model-selector.ts +150 -0
  62. package/src/hooks/chat/use-chat-adapter.ts +20 -8
  63. package/src/hooks/chat/use-chat-models.tsx +79 -74
  64. package/src/hooks/chat/use-chat-permission-mode.ts +14 -10
  65. package/src/hooks/chat/use-chat-session-actions.ts +13 -10
  66. package/src/hooks/chat/use-chat-session-messages.ts +46 -6
  67. package/src/hooks/chat/use-chat-session.ts +42 -1
  68. package/src/hooks/use-app-preferences.ts +41 -0
  69. package/src/hooks/use-session-subscription.ts +101 -0
  70. package/src/hooks/use-sidebar-navigation.ts +35 -0
  71. package/src/resources/locales/en.json +6 -0
  72. package/src/resources/locales/zh.json +6 -0
  73. package/src/routes/AppRoutes.tsx +22 -0
  74. package/src/routes/ArchiveRoute.tsx +5 -0
  75. package/src/routes/AutomationRoute.tsx +5 -0
  76. package/src/routes/BenchmarkRoute.tsx +5 -0
  77. package/src/{components/Chat.scss → routes/ChatRoute.scss} +35 -0
  78. package/src/{components/Chat.tsx → routes/ChatRoute.tsx} +54 -28
  79. package/src/routes/ConfigRoute.tsx +5 -0
  80. package/src/routes/KnowledgeRoute.tsx +5 -0
  81. package/dist/assets/channel-84s1ACzD.js +0 -1
  82. package/dist/assets/clone-B2E8tddE.js +0 -1
  83. package/dist/assets/flowDiagram-v2-4f6560a1-CJfJYbME.js +0 -1
  84. package/dist/assets/index-cGZvDhhU.js +0 -542
  85. /package/src/components/{AutomationView → automation-view}/RuleFormPanel.scss +0 -0
  86. /package/src/components/{AutomationView → automation-view}/RuleFormPanel.tsx +0 -0
  87. /package/src/components/{AutomationView → automation-view}/RuleSidebar.scss +0 -0
  88. /package/src/components/{AutomationView → automation-view}/RuleSidebar.tsx +0 -0
  89. /package/src/components/{AutomationView → automation-view}/RunHistoryPanel.scss +0 -0
  90. /package/src/components/{AutomationView → automation-view}/RunHistoryPanel.tsx +0 -0
  91. /package/src/components/{AutomationView → automation-view}/TaskList.scss +0 -0
  92. /package/src/components/{AutomationView → automation-view}/TaskList.tsx +0 -0
  93. /package/src/components/{AutomationView → automation-view}/TriggerList.scss +0 -0
  94. /package/src/components/{AutomationView → automation-view}/TriggerList.tsx +0 -0
  95. /package/src/components/{AutomationView/AutomationView.scss → automation-view/index.scss} +0 -0
  96. /package/src/components/{AutomationView → automation-view}/types.ts +0 -0
  97. /package/src/components/{BenchmarkView → benchmark-view}/BenchmarkCasePanel.scss +0 -0
  98. /package/src/components/{BenchmarkView → benchmark-view}/BenchmarkCasePanel.tsx +0 -0
  99. /package/src/components/{BenchmarkView → benchmark-view}/BenchmarkSidebar.scss +0 -0
  100. /package/src/components/{BenchmarkView → benchmark-view}/BenchmarkSidebar.tsx +0 -0
  101. /package/src/components/{BenchmarkView → benchmark-view}/BenchmarkView.scss +0 -0
  102. /package/src/components/{BenchmarkView → benchmark-view}/types.ts +0 -0
  103. /package/src/components/{BenchmarkView → benchmark-view}/utils.ts +0 -0
  104. /package/src/components/chat/{Messages → messages}/MessageFooter.tsx +0 -0
  105. /package/src/components/chat/{Messages → messages}/MessageItem.scss +0 -0
  106. /package/src/components/chat/{Messages → messages}/MessageItem.tsx +0 -0
  107. /package/src/components/chat/{Messages → messages}/message-utils.ts +0 -0
  108. /package/src/components/chat/{Sender → sender}/CompletionMenu.scss +0 -0
  109. /package/src/components/chat/{Sender → sender}/CompletionMenu.tsx +0 -0
  110. /package/src/components/chat/{Sender → sender}/ThinkingStatus.scss +0 -0
  111. /package/src/components/chat/{Sender → sender}/ThinkingStatus.tsx +0 -0
  112. /package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/EventList.scss +0 -0
  113. /package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/EventList.tsx +0 -0
  114. /package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/gantt.ts +0 -0
  115. /package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/git-graph.ts +0 -0
  116. /package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/index.scss +0 -0
  117. /package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/index.tsx +0 -0
  118. /package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/mermaid.ts +0 -0
  119. /package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/types.ts +0 -0
  120. /package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/utils.ts +0 -0
  121. /package/src/components/config/{recordEditors → record-editors}/BooleanRecordEditor.scss +0 -0
  122. /package/src/components/config/{recordEditors → record-editors}/BooleanRecordEditor.tsx +0 -0
  123. /package/src/components/config/{recordEditors → record-editors}/ChannelRecordEditor.scss +0 -0
  124. /package/src/components/config/{recordEditors → record-editors}/ChannelRecordEditor.tsx +0 -0
  125. /package/src/components/config/{recordEditors → record-editors}/KeyValueEditor.scss +0 -0
  126. /package/src/components/config/{recordEditors → record-editors}/KeyValueEditor.tsx +0 -0
  127. /package/src/components/config/{recordEditors → record-editors}/McpServersRecordEditor.scss +0 -0
  128. /package/src/components/config/{recordEditors → record-editors}/McpServersRecordEditor.tsx +0 -0
  129. /package/src/components/config/{recordEditors → record-editors}/ModelServicesRecordEditor.scss +0 -0
  130. /package/src/components/config/{recordEditors → record-editors}/ModelServicesRecordEditor.tsx +0 -0
  131. /package/src/components/config/{recordEditors → record-editors}/RecordEditors.scss +0 -0
  132. /package/src/components/config/{recordEditors → record-editors}/RecordJsonEditor.scss +0 -0
  133. /package/src/components/config/{recordEditors → record-editors}/RecordJsonEditor.tsx +0 -0
  134. /package/src/components/config/{recordEditors → record-editors}/index.tsx +0 -0
@@ -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-Cmlqga_E.js";import{a as Qt}from"./createText-1719965b-DwX8iC5F.js";import"./index-cGZvDhhU.js";import{i as Kt}from"./init-Gi6I4Gst.js";import{o as Jt}from"./ordinal-Cboi1Yqb.js";import{l as ft}from"./linear-lDQVZ6aQ.js";import{l as pt}from"./line-CymFqgW6.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-C6sW3GFM.js";import{a as Qt}from"./createText-1719965b-CmOsl1W7.js";import"./index-D37AbgPQ.js";import{i as Kt}from"./init-Gi6I4Gst.js";import{o as Jt}from"./ordinal-Cboi1Yqb.js";import{l as ft}from"./linear-D5iu84ui.js";import{l as pt}from"./line-_lw5YbRM.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
@@ -14,8 +14,8 @@
14
14
  href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200"
15
15
  rel="stylesheet"
16
16
  >
17
- <script type="module" crossorigin src="/__VF_PROJECT_AI_CLIENT_BASE__/assets/index-cGZvDhhU.js"></script>
18
- <link rel="stylesheet" crossorigin href="/__VF_PROJECT_AI_CLIENT_BASE__/assets/index-CHMuZ5-1.css">
17
+ <script type="module" crossorigin src="/__VF_PROJECT_AI_CLIENT_BASE__/assets/index-D37AbgPQ.js"></script>
18
+ <link rel="stylesheet" crossorigin href="/__VF_PROJECT_AI_CLIENT_BASE__/assets/index-fcJ9v94I.css">
19
19
  </head>
20
20
  <body>
21
21
  <div id="root"></div>
package/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "name": "@vibe-forge/client",
3
3
  "type": "module",
4
- "version": "0.5.0",
4
+ "version": "0.6.0",
5
5
  "imports": {
6
6
  "#~/*": [
7
7
  "./src/*",
8
8
  "./src/*.ts",
9
- "./src/*.tsx"
9
+ "./src/*.tsx",
10
+ "./src/*/index.ts",
11
+ "./src/*/index.tsx"
10
12
  ]
11
13
  },
12
14
  "bin": {
@@ -34,12 +36,12 @@
34
36
  "swr": "^2.2.5",
35
37
  "vite": "^5.4.8",
36
38
  "zod": "^3.24.1",
37
- "@vibe-forge/adapter-codex": "^0.5.0",
38
- "@vibe-forge/adapter-claude-code": "^0.5.0",
39
- "@vibe-forge/core": "^0.5.0",
40
- "@vibe-forge/channel-lark": "^0.5.0",
41
- "@vibe-forge/register": "^0.5.0",
42
- "@vibe-forge/plugin-chrome-devtools": "^0.5.0"
39
+ "@vibe-forge/adapter-claude-code": "^0.6.0",
40
+ "@vibe-forge/adapter-codex": "^0.6.0",
41
+ "@vibe-forge/channel-lark": "^0.6.0",
42
+ "@vibe-forge/core": "^0.6.0",
43
+ "@vibe-forge/plugin-chrome-devtools": "^0.6.0",
44
+ "@vibe-forge/register": "^0.6.0"
43
45
  },
44
46
  "devDependencies": {
45
47
  "@types/react": "^18.3.12",
package/src/App.tsx CHANGED
@@ -1,176 +1,28 @@
1
- import { Button, ConfigProvider, Empty, Layout, theme } from 'antd'
2
- import { useAtom, useAtomValue, useSetAtom } from 'jotai'
3
- import React, { useCallback, useEffect } from 'react'
4
- import { useTranslation } from 'react-i18next'
5
- import { Route, Routes, useLocation, useNavigate, useParams } from 'react-router-dom'
6
- import useSWR from 'swr'
1
+ import { ConfigProvider } from 'antd'
7
2
 
8
- import { ArchiveView } from '#~/components/ArchiveView'
9
- import { AutomationView } from '#~/components/AutomationView'
10
- import { BenchmarkView } from '#~/components/BenchmarkView'
11
- import { Chat } from '#~/components/Chat'
12
- import { ConfigView } from '#~/components/ConfigView'
13
- import { KnowledgeBaseView } from '#~/components/knowledge-base'
14
- import { NavRail } from '#~/components/NavRail'
15
- import { Sidebar } from '#~/components/Sidebar'
16
- import type { ConfigResponse, Session } from '@vibe-forge/core'
17
- import { getConfig } from './api'
18
- import { isSidebarResizingAtom, sidebarWidthAtom, themeAtom } from './store/index'
19
-
20
- const MIN_SIDEBAR_WIDTH = 200
21
- const MAX_SIDEBAR_WIDTH = 600
22
-
23
- function ChatView() {
24
- const { t } = useTranslation()
25
- const { sessionId } = useParams()
26
- const navigate = useNavigate()
27
- const { data: sessionsRes } = useSWR<{ sessions: Session[] }>('/api/sessions')
28
- const sessions = sessionsRes?.sessions ?? []
29
- const session = sessions.find(s => s.id === sessionId)
30
-
31
- if (session == null) {
32
- return (
33
- <div style={{ height: '100%', display: 'grid', placeItems: 'center', alignContent: 'center', gap: '16px' }}>
34
- <Empty description={t('common.sessionNotFound')} />
35
- <Button type='primary' onClick={() => navigate('/')}>{t('common.backToHome')}</Button>
36
- </div>
37
- )
38
- }
39
-
40
- return <Chat session={session} />
41
- }
3
+ import { AppShell } from '#~/components/layout/AppShell'
4
+ import { useSessionSubscription } from '#~/hooks/use-session-subscription.js'
5
+ import { useAppPreferences } from '#~/hooks/use-app-preferences'
6
+ import { useSidebarNavigation } from '#~/hooks/use-sidebar-navigation'
7
+ import { AppRoutes } from '#~/routes/AppRoutes'
42
8
 
43
9
  export default function App() {
44
- const { t, i18n } = useTranslation()
45
- const navigate = useNavigate()
46
- const location = useLocation()
47
- const [themeMode] = useAtom(themeAtom)
48
-
49
- const { data: sessionsRes } = useSWR<{ sessions: Session[] }>('/api/sessions')
50
- const { data: configRes } = useSWR<ConfigResponse>('/api/config', getConfig)
51
- const interfaceLanguage = configRes?.sources?.merged?.general?.interfaceLanguage
52
-
53
- const [sidebarWidth, setSidebarWidth] = useAtom(sidebarWidthAtom)
54
- const isResizing = useAtomValue(isSidebarResizingAtom)
55
- const setIsResizing = useSetAtom(isSidebarResizingAtom)
56
-
57
- const currentPath = location.pathname
58
- const activeId = currentPath === '/' ? undefined : currentPath.split('/session/')[1]
59
-
60
- const handleMouseDown = useCallback((e: React.MouseEvent) => {
61
- setIsResizing(true)
62
- e.preventDefault()
63
- }, [])
64
-
65
- const handleMouseMove = useCallback((e: MouseEvent) => {
66
- if (!isResizing) return
67
-
68
- // 获取相对于容器左边缘的坐标
69
- // 容器由 NavRail (56px) + Sidebar 组成
70
- let newWidth = e.clientX - 56
71
- if (newWidth < MIN_SIDEBAR_WIDTH) newWidth = MIN_SIDEBAR_WIDTH
72
- if (newWidth > MAX_SIDEBAR_WIDTH) newWidth = MAX_SIDEBAR_WIDTH
73
-
74
- setSidebarWidth(newWidth)
75
- }, [isResizing, setSidebarWidth])
76
-
77
- const handleMouseUp = useCallback(() => {
78
- setIsResizing(false)
79
- localStorage.setItem('sidebarWidth', sidebarWidth.toString())
80
- }, [sidebarWidth])
81
-
82
- useEffect(() => {
83
- if (isResizing) {
84
- window.addEventListener('mousemove', handleMouseMove)
85
- window.addEventListener('mouseup', handleMouseUp)
86
- document.body.style.cursor = 'col-resize'
87
- } else {
88
- window.removeEventListener('mousemove', handleMouseMove)
89
- window.removeEventListener('mouseup', handleMouseUp)
90
- document.body.style.cursor = ''
91
- }
92
- return () => {
93
- window.removeEventListener('mousemove', handleMouseMove)
94
- window.removeEventListener('mouseup', handleMouseUp)
95
- }
96
- }, [isResizing, handleMouseMove, handleMouseUp])
97
-
98
- const isDarkMode = themeMode === 'dark' ||
99
- (themeMode === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)
100
-
101
- const showSidebar = currentPath === '/' || currentPath.startsWith('/session/')
102
-
103
- const handleDeletedSession = useCallback((deletedId: string, nextId?: string) => {
104
- // 如果删除的不是当前激活的会话,不需要跳转
105
- if (activeId !== deletedId) return
106
-
107
- if (nextId) {
108
- void navigate(`/session/${nextId}`)
109
- } else {
110
- void navigate('/')
111
- }
112
- }, [activeId, navigate])
113
-
114
- useEffect(() => {
115
- if (isDarkMode) {
116
- document.documentElement.classList.add('dark')
117
- } else {
118
- document.documentElement.classList.remove('dark')
119
- }
120
- }, [isDarkMode])
121
-
122
- useEffect(() => {
123
- if (interfaceLanguage && i18n.language !== interfaceLanguage) {
124
- void i18n.changeLanguage(interfaceLanguage)
125
- }
126
- }, [i18n, interfaceLanguage])
10
+ useSessionSubscription()
11
+ const { isDarkMode, themeConfig } = useAppPreferences()
12
+ const sidebarNavigation = useSidebarNavigation()
127
13
 
128
14
  return (
129
- <ConfigProvider
130
- theme={{
131
- algorithm: isDarkMode ? theme.darkAlgorithm : theme.defaultAlgorithm,
132
- token: {
133
- colorPrimary: isDarkMode ? '#3b82f6' : '#000000'
134
- }
135
- }}
136
- >
137
- <Layout style={{ height: '100vh', display: 'flex', flexDirection: 'row', overflow: 'hidden' }}>
138
- <NavRail />
139
- {showSidebar && (
140
- <>
141
- <Sidebar
142
- width={sidebarWidth}
143
- activeId={activeId}
144
- onSelectSession={(session: Session, isNew?: boolean) => {
145
- if (session.id === '') {
146
- void navigate('/')
147
- } else {
148
- void navigate(`/session/${session.id}`)
149
- }
150
- }}
151
- onDeletedSession={handleDeletedSession}
152
- />
153
- </>
154
- )}
155
- <Layout.Content
156
- style={{
157
- flex: 1,
158
- position: 'relative',
159
- overflow: 'hidden',
160
- backgroundColor: isDarkMode ? '#141414' : '#fff'
161
- }}
162
- >
163
- <Routes>
164
- <Route path='/' element={<Chat />} />
165
- <Route path='/session/:sessionId' element={<ChatView />} />
166
- <Route path='/archive' element={<ArchiveView />} />
167
- <Route path='/benchmark' element={<BenchmarkView />} />
168
- <Route path='/automation' element={<AutomationView />} />
169
- <Route path='/knowledge' element={<KnowledgeBaseView />} />
170
- <Route path='/config' element={<ConfigView />} />
171
- </Routes>
172
- </Layout.Content>
173
- </Layout>
15
+ <ConfigProvider theme={themeConfig}>
16
+ <AppShell
17
+ activeSessionId={sidebarNavigation.activeSessionId}
18
+ isDarkMode={isDarkMode}
19
+ onDeletedSession={sidebarNavigation.handleDeletedSession}
20
+ onSelectSession={sidebarNavigation.handleSelectSession}
21
+ showSidebar={sidebarNavigation.showSidebar}
22
+ sidebarWidth={sidebarNavigation.sidebarWidth}
23
+ >
24
+ <AppRoutes />
25
+ </AppShell>
174
26
  </ConfigProvider>
175
27
  )
176
28
  }
package/src/api/base.ts CHANGED
@@ -32,10 +32,124 @@ export const buildApiUrl = (path: string) => {
32
32
 
33
33
  export const createApiUrl = (path: string) => new URL(buildApiUrl(path))
34
34
 
35
+ export interface ApiSuccessEnvelope<T> {
36
+ success: true
37
+ data: T
38
+ }
39
+
40
+ export interface ApiErrorPayload {
41
+ code: string
42
+ message: string
43
+ details?: unknown
44
+ }
45
+
46
+ export interface ApiErrorEnvelope {
47
+ success: false
48
+ error: ApiErrorPayload
49
+ }
50
+
51
+ export class ApiError extends Error {
52
+ status: number
53
+ code: string
54
+ details?: unknown
55
+
56
+ constructor(status: number, payload: ApiErrorPayload) {
57
+ super(payload.message)
58
+ this.name = 'ApiError'
59
+ this.status = status
60
+ this.code = payload.code
61
+ this.details = payload.details
62
+ }
63
+ }
64
+
65
+ const isRecord = (value: unknown): value is Record<string, unknown> => {
66
+ return value != null && typeof value === 'object' && !Array.isArray(value)
67
+ }
68
+
69
+ const isApiSuccessEnvelope = <T>(value: unknown): value is ApiSuccessEnvelope<T> => {
70
+ return isRecord(value) && value.success === true && 'data' in value
71
+ }
72
+
73
+ const isApiErrorEnvelope = (value: unknown): value is ApiErrorEnvelope => {
74
+ return isRecord(value)
75
+ && value.success === false
76
+ && isRecord(value.error)
77
+ && typeof value.error.message === 'string'
78
+ && typeof value.error.code === 'string'
79
+ }
80
+
81
+ const parseResponseBody = async (res: Response): Promise<unknown> => {
82
+ const text = await res.text()
83
+ if (text.trim() === '') {
84
+ return null
85
+ }
86
+ try {
87
+ return JSON.parse(text) as unknown
88
+ } catch {
89
+ return text
90
+ }
91
+ }
92
+
93
+ const toApiError = (status: number, body: unknown, fallbackMessage: string) => {
94
+ if (isApiErrorEnvelope(body)) {
95
+ return new ApiError(status, body.error)
96
+ }
97
+
98
+ if (isRecord(body)) {
99
+ const message = typeof body.error === 'string'
100
+ ? body.error
101
+ : typeof body.message === 'string'
102
+ ? body.message
103
+ : fallbackMessage
104
+ const code = typeof body.code === 'string' ? body.code : 'request_failed'
105
+ return new ApiError(status, {
106
+ code,
107
+ message,
108
+ ...(body.details !== undefined ? { details: body.details } : {})
109
+ })
110
+ }
111
+
112
+ if (typeof body === 'string' && body.trim() !== '') {
113
+ return new ApiError(status, { code: 'request_failed', message: body })
114
+ }
115
+
116
+ return new ApiError(status, { code: 'request_failed', message: fallbackMessage })
117
+ }
118
+
119
+ const unwrapApiResponse = async <T>(res: Response, errorLabel?: string): Promise<T> => {
120
+ const body = await parseResponseBody(res)
121
+ if (!res.ok) {
122
+ const fallbackMessage = errorLabel ?? `Request failed with status ${res.status}`
123
+ const apiError = toApiError(res.status, body, fallbackMessage)
124
+ console.error(errorLabel ?? '[api] request failed', res.status, apiError.message, apiError.details)
125
+ throw apiError
126
+ }
127
+
128
+ if (isApiErrorEnvelope(body)) {
129
+ throw new ApiError(res.status, body.error)
130
+ }
131
+
132
+ if (isApiSuccessEnvelope<T>(body)) {
133
+ return body.data
134
+ }
135
+
136
+ return body as T
137
+ }
138
+
139
+ export const getApiErrorMessage = (error: unknown, fallback: string) => {
140
+ if (error instanceof ApiError && error.message.trim() !== '') {
141
+ return error.message
142
+ }
143
+ if (error instanceof Error && error.message.trim() !== '') {
144
+ return error.message
145
+ }
146
+ return fallback
147
+ }
148
+
35
149
  export async function fetchApiJson<T>(pathOrUrl: string | URL, init?: RequestInit): Promise<T> {
36
150
  const url = typeof pathOrUrl === 'string' ? buildApiUrl(pathOrUrl) : pathOrUrl.toString()
37
151
  const res = await fetch(url, init)
38
- return res.json() as Promise<T>
152
+ return unwrapApiResponse<T>(res)
39
153
  }
40
154
 
41
155
  export async function fetchApiJsonOrThrow<T>(
@@ -45,10 +159,5 @@ export async function fetchApiJsonOrThrow<T>(
45
159
  ): Promise<T> {
46
160
  const url = typeof pathOrUrl === 'string' ? buildApiUrl(pathOrUrl) : pathOrUrl.toString()
47
161
  const res = await fetch(url, init)
48
- if (!res.ok) {
49
- const text = await res.text()
50
- console.error(errorLabel, res.status, text)
51
- throw new Error(`${errorLabel} ${res.status} ${text}`)
52
- }
53
- return res.json() as Promise<T>
162
+ return unwrapApiResponse<T>(res, errorLabel)
54
163
  }
package/src/api.ts CHANGED
@@ -9,6 +9,7 @@ export {
9
9
  updateAutomationRule
10
10
  } from './api/automation'
11
11
 
12
+ export { ApiError, getApiErrorMessage } from './api/base'
12
13
  export {
13
14
  getBenchmarkCase,
14
15
  getBenchmarkResult,
@@ -17,13 +18,14 @@ export {
17
18
  listBenchmarkCategories,
18
19
  startBenchmarkRun
19
20
  } from './api/benchmark'
21
+
20
22
  // 配置读取与更新 API
21
23
  export { getConfig, updateConfig } from './api/config'
22
24
 
23
25
  // 知识库与规则说明 API
24
26
  export type { EntityDetail, EntitySummary, RuleDetail, RuleSummary, SpecDetail, SpecSummary } from './api/knowledge'
25
-
26
27
  export { getEntityDetail, getRuleDetail, getSpecDetail, listEntities, listRules, listSpecs } from './api/knowledge'
28
+
27
29
  // 项目与工程 API
28
30
  export { createProject, listProjects } from './api/projects'
29
31
 
@@ -6,7 +6,7 @@ import dayjs from 'dayjs'
6
6
  import React, { useMemo, useState } from 'react'
7
7
  import { useTranslation } from 'react-i18next'
8
8
  import useSWR from 'swr'
9
- import { deleteSession, listSessions, updateSession } from '../api'
9
+ import { deleteSession, getApiErrorMessage, listSessions, updateSession } from '../api'
10
10
 
11
11
  export function ArchiveView() {
12
12
  const { t } = useTranslation()
@@ -40,7 +40,7 @@ export function ArchiveView() {
40
40
  void message.success(t('common.restoreSuccess', 'Restored successfully'))
41
41
  void mutate()
42
42
  } catch (err) {
43
- void message.error(t('common.restoreFailed', 'Failed to restore'))
43
+ void message.error(getApiErrorMessage(err, t('common.restoreFailed', 'Failed to restore')))
44
44
  }
45
45
  }
46
46
 
@@ -50,7 +50,7 @@ export function ArchiveView() {
50
50
  void message.success(t('common.deleteSuccess', 'Deleted successfully'))
51
51
  void mutate()
52
52
  } catch (err) {
53
- void message.error(t('common.deleteFailed', 'Failed to delete'))
53
+ void message.error(getApiErrorMessage(err, t('common.deleteFailed', 'Failed to delete')))
54
54
  }
55
55
  }
56
56
 
@@ -80,7 +80,7 @@ export function ArchiveView() {
80
80
  setIsBatchMode(false)
81
81
  void mutate()
82
82
  } catch (err) {
83
- void message.error(t('common.batchRestoreFailed', 'Failed to restore some sessions'))
83
+ void message.error(getApiErrorMessage(err, t('common.batchRestoreFailed', 'Failed to restore some sessions')))
84
84
  }
85
85
  }
86
86
 
@@ -92,7 +92,7 @@ export function ArchiveView() {
92
92
  setIsBatchMode(false)
93
93
  void mutate()
94
94
  } catch (err) {
95
- void message.error(t('common.batchDeleteFailed', 'Failed to delete some sessions'))
95
+ void message.error(getApiErrorMessage(err, t('common.batchDeleteFailed', 'Failed to delete some sessions')))
96
96
  }
97
97
  }
98
98
 
@@ -7,7 +7,7 @@ import useSWR from 'swr'
7
7
 
8
8
  import type { AboutInfo, ConfigResponse, ConfigSource } from '@vibe-forge/core'
9
9
 
10
- import { getConfig, updateConfig } from '../api'
10
+ import { getApiErrorMessage, getConfig, updateConfig } from '../api'
11
11
  import { useQueryParams } from '../hooks/useQueryParams'
12
12
  import { AboutSection, ConfigSectionPanel, ConfigSourceSwitch, DisplayValue } from './config'
13
13
  import { AppSettingsPanel } from './config/AppSettingsPanel'
@@ -158,8 +158,8 @@ export function ConfigView() {
158
158
  await updateConfig(source, sectionKey, currentValue)
159
159
  lastSavedRef.current[draftKey] = currentSerialized
160
160
  await mutate()
161
- } catch {
162
- void message.error(t('config.saveFailed'))
161
+ } catch (error) {
162
+ void message.error(getApiErrorMessage(error, t('config.saveFailed')))
163
163
  } finally {
164
164
  savingRef.current[draftKey] = false
165
165
  }
@@ -1,4 +1,4 @@
1
- import './AutomationView.scss'
1
+ import './index.scss'
2
2
 
3
3
  import { App } from 'antd'
4
4
  import React, { useCallback, useEffect, useMemo, useState } from 'react'
@@ -10,6 +10,7 @@ import type { AutomationRule, AutomationRun } from '#~/api.js'
10
10
  import {
11
11
  createAutomationRule,
12
12
  deleteAutomationRule,
13
+ getApiErrorMessage,
13
14
  listAutomationRules,
14
15
  listAutomationRuns,
15
16
  runAutomationRule,
@@ -127,8 +128,8 @@ export function AutomationView() {
127
128
  void mutateRuns()
128
129
  setPanelMode('view')
129
130
  }
130
- } catch {
131
- void message.error(t('automation.saveFailed'))
131
+ } catch (error) {
132
+ void message.error(getApiErrorMessage(error, t('automation.saveFailed')))
132
133
  } finally {
133
134
  setSubmitting(false)
134
135
  }
@@ -143,8 +144,8 @@ export function AutomationView() {
143
144
  }
144
145
  void mutate()
145
146
  void message.success(t('automation.deleted'))
146
- } catch {
147
- void message.error(t('automation.deleteFailed'))
147
+ } catch (error) {
148
+ void message.error(getApiErrorMessage(error, t('automation.deleteFailed')))
148
149
  }
149
150
  }, [message, mutate, selectedRuleId, t])
150
151
 
@@ -157,8 +158,8 @@ export function AutomationView() {
157
158
  void mutateRuns()
158
159
  void navigate(`/session/${nextSessionId}`)
159
160
  }
160
- } catch {
161
- void message.error(t('automation.runFailed'))
161
+ } catch (error) {
162
+ void message.error(getApiErrorMessage(error, t('automation.runFailed')))
162
163
  }
163
164
  }, [message, mutateRuns, navigate, t])
164
165
 
@@ -166,8 +167,8 @@ export function AutomationView() {
166
167
  try {
167
168
  await updateAutomationRule(rule.id, { enabled })
168
169
  void mutate()
169
- } catch {
170
- void message.error(t('automation.toggleFailed'))
170
+ } catch (error) {
171
+ void message.error(getApiErrorMessage(error, t('automation.toggleFailed')))
171
172
  }
172
173
  }, [message, mutate, t])
173
174
 
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next'
6
6
  import useSWR from 'swr'
7
7
 
8
8
  import {
9
+ getApiErrorMessage,
9
10
  getBenchmarkResult,
10
11
  getBenchmarkRun,
11
12
  listBenchmarkCases,
@@ -88,8 +89,8 @@ export function BenchmarkView() {
88
89
  const res = await startBenchmarkRun({ category: item.category, title: item.title })
89
90
  setActiveRunId(res.run.runId)
90
91
  void message.success(t('benchmark.runStarted'))
91
- } catch {
92
- void message.error(t('benchmark.runFailed'))
92
+ } catch (error) {
93
+ void message.error(getApiErrorMessage(error, t('benchmark.runFailed')))
93
94
  }
94
95
  }, [message, t])
95
96
 
@@ -98,8 +99,8 @@ export function BenchmarkView() {
98
99
  const res = await startBenchmarkRun({ category })
99
100
  setActiveRunId(res.run.runId)
100
101
  void message.success(t('benchmark.categoryRunStarted'))
101
- } catch {
102
- void message.error(t('benchmark.runFailed'))
102
+ } catch (error) {
103
+ void message.error(getApiErrorMessage(error, t('benchmark.runFailed')))
103
104
  }
104
105
  }, [message, t])
105
106
 
@@ -7,7 +7,7 @@ import { useAtomValue } from 'jotai'
7
7
  import { useEffect, useMemo, useRef, useState } from 'react'
8
8
  import { useTranslation } from 'react-i18next'
9
9
 
10
- import { deleteSession, updateSession } from '../../api'
10
+ import { deleteSession, getApiErrorMessage, updateSession } from '../../api'
11
11
  import { isSidebarCollapsedAtom, isSidebarResizingAtom } from '../../store/index'
12
12
  import { ConfigSectionPanel } from '../config'
13
13
  import type { FieldSpec } from '../config/configSchema'
@@ -68,7 +68,7 @@ export function ChatHeader({
68
68
  await updateSession(sessionId, { isStarred: !isStarred })
69
69
  void message.success(isStarred ? t('common.unstarred') : t('common.starred'))
70
70
  } catch (err) {
71
- void message.error(t('common.operationFailed'))
71
+ void message.error(getApiErrorMessage(err, t('common.operationFailed')))
72
72
  }
73
73
  }
74
74
 
@@ -78,7 +78,7 @@ export function ChatHeader({
78
78
  await updateSession(sessionId, { isArchived: !isArchived })
79
79
  void message.success(isArchived ? t('common.restored') : t('common.archived'))
80
80
  } catch (err) {
81
- void message.error(t('common.operationFailed'))
81
+ void message.error(getApiErrorMessage(err, t('common.operationFailed')))
82
82
  }
83
83
  }
84
84
 
@@ -257,8 +257,8 @@ export function SessionSettingsPanel({
257
257
  tags: Array.isArray(currentValue.tags) ? currentValue.tags : []
258
258
  })
259
259
  lastSavedRef.current = currentSerialized
260
- } catch {
261
- void message.error(t('common.operationFailed'))
260
+ } catch (err) {
261
+ void message.error(getApiErrorMessage(err, t('common.operationFailed')))
262
262
  } finally {
263
263
  savingRef.current = false
264
264
  }
@@ -292,7 +292,7 @@ export function SessionSettingsPanel({
292
292
  void message.success(t('common.deleteSuccess'))
293
293
  onClose()
294
294
  } catch (err) {
295
- void message.error(t('common.deleteFailed'))
295
+ void message.error(getApiErrorMessage(err, t('common.deleteFailed')))
296
296
  }
297
297
  }
298
298
  })