@vibe-forge/client 0.4.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 (142) hide show
  1. package/AGENTS.md +37 -0
  2. package/cli.cjs +1 -0
  3. package/dist/assets/{arc-DgIxeTMg.js → arc-CMAHd5G3.js} +1 -1
  4. package/dist/assets/{blockDiagram-c4efeb88-CEAob3X9.js → blockDiagram-c4efeb88-DKww-VCP.js} +1 -1
  5. package/dist/assets/{c4Diagram-c83219d4-DwIxpDKd.js → c4Diagram-c83219d4-DKrjVHyY.js} +1 -1
  6. package/dist/assets/channel-Bi4g8rj9.js +1 -0
  7. package/dist/assets/{classDiagram-beda092f-Cz1q8u_0.js → classDiagram-beda092f-BXx5rdo3.js} +1 -1
  8. package/dist/assets/{classDiagram-v2-2358418a-CImgTuwd.js → classDiagram-v2-2358418a-CnR3WLsr.js} +1 -1
  9. package/dist/assets/clone-DPrpP2ky.js +1 -0
  10. package/dist/assets/{createText-1719965b-C1_HJcCc.js → createText-1719965b-CmOsl1W7.js} +1 -1
  11. package/dist/assets/{edges-96097737-BU8qStzd.js → edges-96097737-CQeQgpjD.js} +1 -1
  12. package/dist/assets/{erDiagram-0228fc6a-DNA1Fz2L.js → erDiagram-0228fc6a-ZUNB-ucF.js} +1 -1
  13. package/dist/assets/{flowDb-c6c81e3f-DjiCStMN.js → flowDb-c6c81e3f-DuuKeSLX.js} +1 -1
  14. package/dist/assets/{flowDiagram-50d868cf-CSDi0-RD.js → flowDiagram-50d868cf-Bc6n85yR.js} +1 -1
  15. package/dist/assets/flowDiagram-v2-4f6560a1-BZqaeqoh.js +1 -0
  16. package/dist/assets/{flowchart-elk-definition-6af322e1-DrhIMas7.js → flowchart-elk-definition-6af322e1-cAG5afW9.js} +1 -1
  17. package/dist/assets/{ganttDiagram-a2739b55-CTZnUP5z.js → ganttDiagram-a2739b55-Dp6xhY5I.js} +1 -1
  18. package/dist/assets/{gitGraphDiagram-82fe8481-COOW7jTi.js → gitGraphDiagram-82fe8481-MlIIRBdG.js} +1 -1
  19. package/dist/assets/{graph-CIkpD4Kx.js → graph-D7Es8jZ-.js} +1 -1
  20. package/dist/assets/{index-5325376f-aVVRRTIu.js → index-5325376f-DC18ottv.js} +1 -1
  21. package/dist/assets/index-D37AbgPQ.js +545 -0
  22. package/dist/assets/{index-D1giUI7r.css → index-fcJ9v94I.css} +1 -1
  23. package/dist/assets/{infoDiagram-8eee0895-DQpZ1LVD.js → infoDiagram-8eee0895-CXk21kFp.js} +1 -1
  24. package/dist/assets/{journeyDiagram-c64418c1-DoKguIuk.js → journeyDiagram-c64418c1-899BKBHL.js} +1 -1
  25. package/dist/assets/{layout-Tnmha8Nh.js → layout-DLaxdy48.js} +1 -1
  26. package/dist/assets/{line-BQR2SOyl.js → line-_lw5YbRM.js} +1 -1
  27. package/dist/assets/{linear-DlG0eemV.js → linear-D5iu84ui.js} +1 -1
  28. package/dist/assets/{mermaid.core-BnwYO0He.js → mermaid.core-C6sW3GFM.js} +4 -4
  29. package/dist/assets/{mindmap-definition-8da855dc-BllYwDID.js → mindmap-definition-8da855dc-BS9Xy9KN.js} +1 -1
  30. package/dist/assets/{pieDiagram-a8764435-DwCkhPVc.js → pieDiagram-a8764435-DZt9cEgs.js} +1 -1
  31. package/dist/assets/{quadrantDiagram-1e28029f-c40GKTU0.js → quadrantDiagram-1e28029f-BTIeHOgn.js} +1 -1
  32. package/dist/assets/{requirementDiagram-08caed73-DnQp2Tk6.js → requirementDiagram-08caed73-BHJAKD2g.js} +1 -1
  33. package/dist/assets/{sankeyDiagram-a04cb91d-CnJrs13b.js → sankeyDiagram-a04cb91d-DnAkVOK8.js} +1 -1
  34. package/dist/assets/{sequenceDiagram-c5b8d532-1YBwnpKu.js → sequenceDiagram-c5b8d532-92tE3oFv.js} +1 -1
  35. package/dist/assets/{stateDiagram-1ecb1508-BFBxQ6Fh.js → stateDiagram-1ecb1508-DG0ObiMg.js} +1 -1
  36. package/dist/assets/{stateDiagram-v2-c2b004d7-Dmechvv2.js → stateDiagram-v2-c2b004d7-BKoJx2ci.js} +1 -1
  37. package/dist/assets/{styles-b4e223ce-DWWfWX8O.js → styles-b4e223ce-Ba6G4ri9.js} +1 -1
  38. package/dist/assets/{styles-ca3715f6-CKKvZxaU.js → styles-ca3715f6-Bn6RIIVW.js} +1 -1
  39. package/dist/assets/{styles-d45a18b0-dKMOUh9p.js → styles-d45a18b0-_dELBUI6.js} +1 -1
  40. package/dist/assets/{svgDrawCommon-b86b1483-CBgjChPM.js → svgDrawCommon-b86b1483-CRK-ZoIs.js} +1 -1
  41. package/dist/assets/{timeline-definition-faaaa080-NCt-HHmb.js → timeline-definition-faaaa080-DvQ_RA_i.js} +1 -1
  42. package/dist/assets/{xychartDiagram-f5964ef8-BJhXS4dG.js → xychartDiagram-f5964ef8-CJxeDLfg.js} +1 -1
  43. package/dist/index.html +2 -2
  44. package/package.json +10 -7
  45. package/src/App.tsx +20 -168
  46. package/src/api/base.ts +116 -7
  47. package/src/api/sessions.ts +3 -1
  48. package/src/api.ts +3 -1
  49. package/src/components/ArchiveView.tsx +5 -5
  50. package/src/components/ConfigView.tsx +28 -28
  51. package/src/components/{AutomationView → automation-view}/index.tsx +10 -9
  52. package/src/components/{BenchmarkView → benchmark-view}/index.tsx +5 -4
  53. package/src/components/chat/ChatHeader.tsx +6 -6
  54. package/src/components/chat/ChatHistoryView.tsx +74 -16
  55. package/src/components/chat/ChatTimelineView.tsx +3 -3
  56. package/src/components/chat/CurrentTodoList.scss +56 -27
  57. package/src/components/chat/{Sender → sender}/Sender.scss +278 -85
  58. package/src/components/chat/{Sender → sender}/Sender.tsx +125 -41
  59. package/src/components/chat/tools/core/ToolGroup.tsx +1 -1
  60. package/src/components/config/ConfigSectionForm.tsx +1 -1
  61. package/src/components/config/ConfigSourceSwitch.tsx +12 -34
  62. package/src/components/config/channelDefinitions.ts +2 -2
  63. package/src/components/layout/AppShell.scss +19 -0
  64. package/src/components/layout/AppShell.tsx +45 -0
  65. package/src/components/sidebar/SessionItem.scss +17 -0
  66. package/src/components/sidebar/SessionItem.tsx +21 -13
  67. package/src/hooks/chat/model-selector.ts +150 -0
  68. package/src/hooks/chat/use-chat-adapter.ts +93 -0
  69. package/src/hooks/chat/use-chat-models.tsx +126 -57
  70. package/src/hooks/chat/use-chat-permission-mode.ts +14 -10
  71. package/src/hooks/chat/use-chat-session-actions.ts +22 -13
  72. package/src/hooks/chat/use-chat-session-messages.ts +62 -10
  73. package/src/hooks/chat/use-chat-session.ts +49 -2
  74. package/src/hooks/use-app-preferences.ts +41 -0
  75. package/src/hooks/use-session-subscription.ts +101 -0
  76. package/src/hooks/use-sidebar-navigation.ts +35 -0
  77. package/src/resources/adapters.ts +20 -0
  78. package/src/resources/locales/en.json +6 -0
  79. package/src/resources/locales/zh.json +6 -0
  80. package/src/routes/AppRoutes.tsx +22 -0
  81. package/src/routes/ArchiveRoute.tsx +5 -0
  82. package/src/routes/AutomationRoute.tsx +5 -0
  83. package/src/routes/BenchmarkRoute.tsx +5 -0
  84. package/src/{components/Chat.scss → routes/ChatRoute.scss} +35 -0
  85. package/src/routes/ChatRoute.tsx +132 -0
  86. package/src/routes/ConfigRoute.tsx +5 -0
  87. package/src/routes/KnowledgeRoute.tsx +5 -0
  88. package/dist/assets/channel-DhtnrNJ6.js +0 -1
  89. package/dist/assets/clone-7bHB6YkC.js +0 -1
  90. package/dist/assets/flowDiagram-v2-4f6560a1-_13Sz5Wh.js +0 -1
  91. package/dist/assets/index-DRSI_ZIL.js +0 -514
  92. package/src/components/Chat.tsx +0 -100
  93. package/src/components/{AutomationView → automation-view}/RuleFormPanel.scss +0 -0
  94. package/src/components/{AutomationView → automation-view}/RuleFormPanel.tsx +0 -0
  95. package/src/components/{AutomationView → automation-view}/RuleSidebar.scss +0 -0
  96. package/src/components/{AutomationView → automation-view}/RuleSidebar.tsx +0 -0
  97. package/src/components/{AutomationView → automation-view}/RunHistoryPanel.scss +0 -0
  98. package/src/components/{AutomationView → automation-view}/RunHistoryPanel.tsx +0 -0
  99. package/src/components/{AutomationView → automation-view}/TaskList.scss +0 -0
  100. package/src/components/{AutomationView → automation-view}/TaskList.tsx +0 -0
  101. package/src/components/{AutomationView → automation-view}/TriggerList.scss +0 -0
  102. package/src/components/{AutomationView → automation-view}/TriggerList.tsx +0 -0
  103. package/src/components/{AutomationView/AutomationView.scss → automation-view/index.scss} +0 -0
  104. package/src/components/{AutomationView → automation-view}/types.ts +0 -0
  105. package/src/components/{BenchmarkView → benchmark-view}/BenchmarkCasePanel.scss +0 -0
  106. package/src/components/{BenchmarkView → benchmark-view}/BenchmarkCasePanel.tsx +0 -0
  107. package/src/components/{BenchmarkView → benchmark-view}/BenchmarkSidebar.scss +0 -0
  108. package/src/components/{BenchmarkView → benchmark-view}/BenchmarkSidebar.tsx +0 -0
  109. package/src/components/{BenchmarkView → benchmark-view}/BenchmarkView.scss +0 -0
  110. package/src/components/{BenchmarkView → benchmark-view}/types.ts +0 -0
  111. package/src/components/{BenchmarkView → benchmark-view}/utils.ts +0 -0
  112. package/src/components/chat/{Messages → messages}/MessageFooter.tsx +0 -0
  113. package/src/components/chat/{Messages → messages}/MessageItem.scss +0 -0
  114. package/src/components/chat/{Messages → messages}/MessageItem.tsx +0 -0
  115. package/src/components/chat/{Messages → messages}/message-utils.ts +0 -0
  116. package/src/components/chat/{Sender → sender}/CompletionMenu.scss +0 -0
  117. package/src/components/chat/{Sender → sender}/CompletionMenu.tsx +0 -0
  118. package/src/components/chat/{Sender → sender}/ThinkingStatus.scss +0 -0
  119. package/src/components/chat/{Sender → sender}/ThinkingStatus.tsx +0 -0
  120. package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/EventList.scss +0 -0
  121. package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/EventList.tsx +0 -0
  122. package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/gantt.ts +0 -0
  123. package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/git-graph.ts +0 -0
  124. package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/index.scss +0 -0
  125. package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/index.tsx +0 -0
  126. package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/mermaid.ts +0 -0
  127. package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/types.ts +0 -0
  128. package/src/components/chat/{SessionTimelinePanel → session-timeline-panel}/utils.ts +0 -0
  129. package/src/components/config/{recordEditors → record-editors}/BooleanRecordEditor.scss +0 -0
  130. package/src/components/config/{recordEditors → record-editors}/BooleanRecordEditor.tsx +0 -0
  131. package/src/components/config/{recordEditors → record-editors}/ChannelRecordEditor.scss +0 -0
  132. package/src/components/config/{recordEditors → record-editors}/ChannelRecordEditor.tsx +33 -33
  133. /package/src/components/config/{recordEditors → record-editors}/KeyValueEditor.scss +0 -0
  134. /package/src/components/config/{recordEditors → record-editors}/KeyValueEditor.tsx +0 -0
  135. /package/src/components/config/{recordEditors → record-editors}/McpServersRecordEditor.scss +0 -0
  136. /package/src/components/config/{recordEditors → record-editors}/McpServersRecordEditor.tsx +0 -0
  137. /package/src/components/config/{recordEditors → record-editors}/ModelServicesRecordEditor.scss +0 -0
  138. /package/src/components/config/{recordEditors → record-editors}/ModelServicesRecordEditor.tsx +0 -0
  139. /package/src/components/config/{recordEditors → record-editors}/RecordEditors.scss +0 -0
  140. /package/src/components/config/{recordEditors → record-editors}/RecordJsonEditor.scss +0 -0
  141. /package/src/components/config/{recordEditors → record-editors}/RecordJsonEditor.tsx +0 -0
  142. /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-BnwYO0He.js";import{a as Qt}from"./createText-1719965b-C1_HJcCc.js";import"./index-DRSI_ZIL.js";import{i as Kt}from"./init-Gi6I4Gst.js";import{o as Jt}from"./ordinal-Cboi1Yqb.js";import{l as ft}from"./linear-DlG0eemV.js";import{l as pt}from"./line-BQR2SOyl.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-DRSI_ZIL.js"></script>
18
- <link rel="stylesheet" crossorigin href="/__VF_PROJECT_AI_CLIENT_BASE__/assets/index-D1giUI7r.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.4.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,11 +36,12 @@
34
36
  "swr": "^2.2.5",
35
37
  "vite": "^5.4.8",
36
38
  "zod": "^3.24.1",
37
- "@vibe-forge/channel-lark": "^0.4.0",
38
- "@vibe-forge/core": "^0.4.0",
39
- "@vibe-forge/plugin-chrome-devtools": "^0.4.0",
40
- "@vibe-forge/adapter-claude-code": "^0.4.0",
41
- "@vibe-forge/register": "^0.4.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"
42
45
  },
43
46
  "devDependencies": {
44
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
  }
@@ -22,6 +22,7 @@ export async function createSession(
22
22
  promptType?: 'spec' | 'entity'
23
23
  promptName?: string
24
24
  permissionMode?: 'default' | 'acceptEdits' | 'plan' | 'dontAsk' | 'bypassPermissions'
25
+ adapter?: string
25
26
  }
26
27
  ): Promise<{ session: Session }> {
27
28
  return fetchApiJson<{ session: Session }>('/api/sessions', {
@@ -37,7 +38,8 @@ export async function createSession(
37
38
  id: options?.id,
38
39
  promptType: options?.promptType,
39
40
  promptName: options?.promptName,
40
- permissionMode: options?.permissionMode
41
+ permissionMode: options?.permissionMode,
42
+ adapter: options?.adapter
41
43
  })
42
44
  })
43
45
  }
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,8 @@ 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
+ import { useQueryParams } from '../hooks/useQueryParams'
11
12
  import { AboutSection, ConfigSectionPanel, ConfigSourceSwitch, DisplayValue } from './config'
12
13
  import { AppSettingsPanel } from './config/AppSettingsPanel'
13
14
  import { cloneValue, getValueByPath, isEmptyValue } from './config/configUtils'
@@ -16,8 +17,12 @@ export function ConfigView() {
16
17
  const { t } = useTranslation()
17
18
  const { message } = App.useApp()
18
19
  const { data, isLoading, error, mutate } = useSWR<ConfigResponse>('/api/config', getConfig)
19
- const [sourceKey, setSourceKey] = useState<ConfigSource>('project')
20
- const [activeTabKey, setActiveTabKey] = useState('general')
20
+ const { values: queryValues, update: updateQuery, searchParams } = useQueryParams<{ tab: string; source: string }>({
21
+ keys: ['tab', 'source'],
22
+ defaults: { tab: 'general', source: 'project' },
23
+ })
24
+ const sourceKey: ConfigSource = queryValues.source === 'user' ? 'user' : 'project'
25
+ const setSourceKey = (next: ConfigSource) => updateQuery({ source: next })
21
26
  const [drafts, setDrafts] = useState<Record<string, unknown>>({})
22
27
  const configPresent = data?.meta?.configPresent
23
28
  const currentSource = data?.sources?.[sourceKey]
@@ -33,10 +38,11 @@ export function ConfigView() {
33
38
  ])
34
39
 
35
40
  useEffect(() => {
41
+ if (searchParams.get('source') != null) return
36
42
  if (configPresent?.project) {
37
- setSourceKey('project')
43
+ updateQuery({ source: 'project' })
38
44
  } else if (configPresent?.user) {
39
- setSourceKey('user')
45
+ updateQuery({ source: 'user' })
40
46
  }
41
47
  }, [configPresent?.project, configPresent?.user])
42
48
 
@@ -89,26 +95,10 @@ export function ConfigView() {
89
95
  ], [currentSource, data?.meta?.about, data?.meta?.experiments, t])
90
96
  const tabKeys = useMemo(() => new Set(tabs.filter(tab => tab.type !== 'group').map(tab => tab.key)), [tabs])
91
97
 
92
- const activeTab = useMemo(() => tabs.find(tab => tab.key === activeTabKey), [tabs, activeTabKey])
93
-
94
- const initializedTabRef = useRef(false)
95
- useEffect(() => {
96
- if (initializedTabRef.current) return
97
- const params = new URLSearchParams(window.location.search)
98
- const tabKey = params.get('tab')
99
- if (tabKey != null && tabKeys.has(tabKey)) {
100
- setActiveTabKey(tabKey)
101
- }
102
- initializedTabRef.current = true
103
- }, [tabKeys])
98
+ const activeTabKey = tabKeys.has(queryValues.tab) ? queryValues.tab : 'general'
99
+ const setActiveTabKey = (key: string) => updateQuery({ tab: key })
104
100
 
105
- useEffect(() => {
106
- if (!tabKeys.has(activeTabKey)) return
107
- const params = new URLSearchParams(window.location.search)
108
- params.set('tab', activeTabKey)
109
- const nextUrl = `${window.location.pathname}?${params.toString()}${window.location.hash}`
110
- window.history.replaceState(null, '', nextUrl)
111
- }, [activeTabKey, tabKeys])
101
+ const activeTab = useMemo(() => tabs.find(tab => tab.key === activeTabKey), [tabs, activeTabKey])
112
102
 
113
103
  useEffect(() => {
114
104
  if (activeTab == null) return
@@ -168,8 +158,8 @@ export function ConfigView() {
168
158
  await updateConfig(source, sectionKey, currentValue)
169
159
  lastSavedRef.current[draftKey] = currentSerialized
170
160
  await mutate()
171
- } catch {
172
- void message.error(t('config.saveFailed'))
161
+ } catch (error) {
162
+ void message.error(getApiErrorMessage(error, t('config.saveFailed')))
173
163
  } finally {
174
164
  savingRef.current[draftKey] = false
175
165
  }
@@ -251,8 +241,18 @@ export function ConfigView() {
251
241
  <ConfigSourceSwitch
252
242
  value={sourceKey}
253
243
  onChange={setSourceKey}
254
- configPresent={configPresent}
255
- t={t}
244
+ options={[
245
+ {
246
+ value: 'project',
247
+ icon: 'folder',
248
+ label: configPresent?.project === true ? t('config.sources.project') : t('config.sources.projectMissing')
249
+ },
250
+ {
251
+ value: 'user',
252
+ icon: 'person',
253
+ label: configPresent?.user === true ? t('config.sources.user') : t('config.sources.userMissing')
254
+ }
255
+ ]}
256
256
  />
257
257
  </Space>
258
258
  )}