@customize-agent/server 4.0.94 → 4.0.95
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.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +25 -57
- package/.next/prerender-manifest.json +3 -3
- package/.next/routes-manifest.json +0 -12
- package/.next/server/chunks/1936.js +2 -2
- package/.next/server/chunks/5840.js +1 -0
- package/.next/server/chunks/6041.js +176 -0
- package/.next/server/chunks/8204.js +1 -1
- package/.next/server/chunks/8661.js +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages/api/assets/generated/preview.js +1 -1
- package/.next/server/pages/api/assets/generated/preview.js.nft.json +1 -1
- package/.next/server/pages/api/assets/generated.js +1 -1
- package/.next/server/pages/api/assets/generated.js.nft.json +1 -1
- package/.next/server/pages/api/config/web-access.js +1 -0
- package/.next/server/pages/api/config/web-access.js.nft.json +1 -0
- package/.next/server/pages/api/documents/chapter/regenerate.js +1 -1
- package/.next/server/pages/api/documents/chapter/regenerate.js.nft.json +1 -1
- package/.next/server/pages/api/documents/export.js +1 -1
- package/.next/server/pages/api/documents/export.js.nft.json +1 -1
- package/.next/server/pages/api/documents/generate.js +2 -2
- package/.next/server/pages/api/documents/generate.js.nft.json +1 -1
- package/.next/server/pages/api/documents/generated/[id].js +1 -1
- package/.next/server/pages/api/documents/generated/[id].js.nft.json +1 -1
- package/.next/server/pages/api/documents/generated.js +1 -1
- package/.next/server/pages/api/documents/generated.js.nft.json +1 -1
- package/.next/server/pages/api/documents/roles.js +1 -1
- package/.next/server/pages/api/documents/roles.js.nft.json +1 -1
- package/.next/server/pages/api/documents/templates.js +1 -1
- package/.next/server/pages/api/documents/templates.js.nft.json +1 -1
- package/.next/server/pages/asset-library.html +1 -1
- package/.next/server/pages/document-roles.html +1 -1
- package/.next/server/pages/documents.html +1 -1
- package/.next/server/pages/guide.html +1 -1
- package/.next/server/pages/index.html +1 -1
- package/.next/server/pages/knowledge/file-detail.html +1 -1
- package/.next/server/pages/knowledge/files.html +1 -1
- package/.next/server/pages/knowledge/manage.html +1 -1
- package/.next/server/pages/knowledge/search.html +1 -1
- package/.next/server/pages/knowledge.html +1 -1
- package/.next/server/pages/models.html +1 -1
- package/.next/server/pages/overview.html +1 -1
- package/.next/server/pages/prompt.html +1 -1
- package/.next/server/pages/settings.html +1 -1
- package/.next/server/pages/system/logs.html +1 -1
- package/.next/server/pages-manifest.json +25 -27
- package/.next/static/3nHhxjRVb6Sv1RCvTTJ6o/_buildManifest.js +1 -0
- package/.next/static/chunks/192-dee7faefaf840b17.js +1 -0
- package/.next/static/chunks/238-4ad320af4f787bd6.js +1 -0
- package/.next/static/chunks/405-74ecbacd0b5a3128.js +8 -0
- package/.next/static/chunks/621-1c48b0d6d904f023.js +4 -0
- package/.next/static/chunks/{795-d8fb7a0420512701.js → 795-e8cfd56df2293576.js} +1 -1
- package/.next/static/chunks/{455-97ad88d6604f54b7.js → 797-9166f495bb6138e3.js} +1 -1
- package/.next/static/chunks/pages/{_app-e1434faf3490a025.js → _app-d0d7f3a02373fa7e.js} +14 -14
- package/.next/static/chunks/pages/{asset-library-37f844cb358f5457.js → asset-library-c744f6c91b24629f.js} +1 -1
- package/.next/static/chunks/pages/{document-roles-6134d2d3284a530a.js → document-roles-5108efe16c9b0dd0.js} +1 -1
- package/.next/static/chunks/pages/documents-1fad70e8cff2eff9.js +1 -0
- package/.next/static/chunks/pages/guide-e00b6e23a8dd41b3.js +1 -0
- package/.next/static/chunks/pages/knowledge/{file-detail-87669392540614e4.js → file-detail-44e52d9e351e8784.js} +1 -1
- package/.next/static/chunks/pages/knowledge/{files-14ef1012fd201e47.js → files-4f7bacb11528982e.js} +1 -1
- package/.next/static/chunks/pages/knowledge/{manage-ed99a6cb254ddbb7.js → manage-205647551376b193.js} +1 -1
- package/.next/static/chunks/pages/knowledge/{search-afb423fc22eb623b.js → search-577f08171a786578.js} +1 -1
- package/.next/static/chunks/pages/models-47a9542ac5bec5c0.js +1 -0
- package/.next/static/chunks/pages/{prompt-9b869fbe3463020d.js → prompt-aad4329e419fb442.js} +1 -1
- package/.next/static/chunks/pages/{settings-fa9d6a56898ba678.js → settings-78d0d5322fd61afe.js} +1 -1
- package/.next/static/chunks/pages/system/{logs-cbeeb77dc70086ae.js → logs-c97311a24d1a67e1.js} +1 -1
- package/messages/en-US.json +0 -16
- package/messages/zh-CN.json +0 -16
- package/package.json +8 -4
- package/scripts/start-server.cjs +79 -0
- package/scripts/upload-matrix.cjs +258 -0
- package/.next/server/chunks/7111.js +0 -182
- package/.next/server/chunks/7899.js +0 -1
- package/.next/server/pages/api/context.js +0 -11
- package/.next/server/pages/api/context.js.nft.json +0 -1
- package/.next/server/pages/context/long-term.html +0 -1
- package/.next/server/pages/context/long-term.js.nft.json +0 -1
- package/.next/server/pages/context/short-term.html +0 -1
- package/.next/server/pages/context/short-term.js.nft.json +0 -1
- package/.next/static/4gglXEsvX5p_wlAU1zB1F/_buildManifest.js +0 -1
- package/.next/static/chunks/466-1cd359f130473697.js +0 -1
- package/.next/static/chunks/63-dd8eeb8edd766bae.js +0 -4
- package/.next/static/chunks/642-708b928fbafc6c20.js +0 -8
- package/.next/static/chunks/647-d5e08fda405f7059.js +0 -1
- package/.next/static/chunks/932-2f195f4200ce9378.js +0 -1
- package/.next/static/chunks/pages/context/long-term-29cbf51a281951d9.js +0 -1
- package/.next/static/chunks/pages/context/short-term-fcae99e1744d998a.js +0 -1
- package/.next/static/chunks/pages/documents-aa14e6ec02784787.js +0 -1
- package/.next/static/chunks/pages/guide-c00be7803483b703.js +0 -1
- package/.next/static/chunks/pages/models-e2914678369d2823.js +0 -1
- /package/.next/static/{4gglXEsvX5p_wlAU1zB1F → 3nHhxjRVb6Sv1RCvTTJ6o}/_ssgManifest.js +0 -0
package/.next/static/chunks/pages/system/{logs-cbeeb77dc70086ae.js → logs-c97311a24d1a67e1.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[979],{14995:(e,t)=>{"use strict";t.A={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M909.1 209.3l-56.4 44.1C775.8 155.1 656.2 92 521.9 92 290 92 102.3 279.5 102 511.5 101.7 743.7 289.8 932 521.9 932c181.3 0 335.8-115 394.6-276.1 1.5-4.2-.7-8.9-4.9-10.3l-56.7-19.5a8 8 0 00-10.1 4.8c-1.8 5-3.8 10-5.9 14.9-17.3 41-42.1 77.8-73.7 109.4A344.77 344.77 0 01655.9 829c-42.3 17.9-87.4 27-133.8 27-46.5 0-91.5-9.1-133.8-27A341.5 341.5 0 01279 755.2a342.16 342.16 0 01-73.7-109.4c-17.9-42.4-27-87.4-27-133.9s9.1-91.5 27-133.9c17.3-41 42.1-77.8 73.7-109.4 31.6-31.6 68.4-56.4 109.3-73.8 42.3-17.9 87.4-27 133.8-27 46.5 0 91.5 9.1 133.8 27a341.5 341.5 0 01109.3 73.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.6 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c-.1-6.6-7.8-10.3-13-6.2z"}}]},name:"reload",theme:"outlined"}},39214:(e,t,r)=>{(window.__NEXT_P=window.__NEXT_P||[]).push(["/system/logs",function(){return r(91698)}])},91698:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>k});var a=r(65321),s=r(97109),i=r(35292),n=r(9137),l=r(11702),o=r(88762),c=r(33442),d=r(85114),h=r(26171),p=r(85493),g=r(7576),u=r(21289),x=r(84253),f=r(99811),y=r(58209),m=r(96651),w=r(60470),j=r(
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[979],{14995:(e,t)=>{"use strict";t.A={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M909.1 209.3l-56.4 44.1C775.8 155.1 656.2 92 521.9 92 290 92 102.3 279.5 102 511.5 101.7 743.7 289.8 932 521.9 932c181.3 0 335.8-115 394.6-276.1 1.5-4.2-.7-8.9-4.9-10.3l-56.7-19.5a8 8 0 00-10.1 4.8c-1.8 5-3.8 10-5.9 14.9-17.3 41-42.1 77.8-73.7 109.4A344.77 344.77 0 01655.9 829c-42.3 17.9-87.4 27-133.8 27-46.5 0-91.5-9.1-133.8-27A341.5 341.5 0 01279 755.2a342.16 342.16 0 01-73.7-109.4c-17.9-42.4-27-87.4-27-133.9s9.1-91.5 27-133.9c17.3-41 42.1-77.8 73.7-109.4 31.6-31.6 68.4-56.4 109.3-73.8 42.3-17.9 87.4-27 133.8-27 46.5 0 91.5 9.1 133.8 27a341.5 341.5 0 01109.3 73.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.6 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c-.1-6.6-7.8-10.3-13-6.2z"}}]},name:"reload",theme:"outlined"}},39214:(e,t,r)=>{(window.__NEXT_P=window.__NEXT_P||[]).push(["/system/logs",function(){return r(91698)}])},91698:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>k});var a=r(65321),s=r(97109),i=r(35292),n=r(9137),l=r(11702),o=r(88762),c=r(33442),d=r(85114),h=r(26171),p=r(85493),g=r(7576),u=r(21289),x=r(84253),f=r(99811),y=r(58209),m=r(96651),w=r(60470),j=r(44494),v=r(6578);let{Text:A,Paragraph:b}=i.A;function k(){let e=(0,j.Vr)(),[t,r]=(0,s.useState)([]),[i,k]=(0,s.useState)(!0),[S,z]=(0,s.useState)(""),[I,C]=(0,s.useState)(!1),N=async()=>{k(!0);try{r((await (0,v.oH)(500)).logs)}catch(e){n.Ay.error(e instanceof Error?e.message:"加载日志失败")}finally{k(!1)}};(0,s.useEffect)(()=>{N()},[]);let B=(0,s.useMemo)(()=>{let e=S.trim().toLowerCase();return e?t.filter(t=>[t.id,t.level,t.source,t.functionName,t.message,t.stack].filter(Boolean).some(t=>String(t).toLowerCase().includes(e))):t},[S,t]),O=[{title:"序号",key:"index",width:70,render:(e,t,r)=>r+1},{title:"时间",dataIndex:"createdAt",width:170,render:e=>new Date(e).toLocaleString()},{title:"级别",dataIndex:"level",width:80,render:e=>(0,a.jsx)(l.A,{color:"error"===e?"error":"warn"===e?"warning":"blue",style:{margin:0},children:e})},{title:"来源",dataIndex:"source",width:200,render:e=>(0,a.jsx)(A,{code:!0,style:{fontSize:12},children:e})},{title:"函数",dataIndex:"functionName",width:160,render:e=>e?(0,a.jsx)(A,{code:!0,style:{fontSize:12},children:e}):(0,a.jsx)(A,{type:"secondary",children:"-"})},{title:"错误信息",dataIndex:"message",render:e=>(0,a.jsx)(b,{style:{maxWidth:480,overflowWrap:"anywhere",wordBreak:"break-all",marginBottom:0,fontSize:12},ellipsis:{rows:2,expandable:!0,symbol:"展开"},children:e})},{title:"Request ID",dataIndex:"id",width:200,render:e=>(0,a.jsx)(A,{copyable:!0,code:!0,style:{fontSize:12},children:e.slice(0,8)})}];return i&&0===t.length?(0,a.jsxs)("div",{className:"space-y-5 animateFadeIn",children:[(0,a.jsx)(o.A,{active:!0,title:!0,paragraph:{rows:1}}),(0,a.jsx)(o.A,{active:!0,paragraph:{rows:12}})]}):(0,a.jsxs)("div",{className:"space-y-5 animateFadeIn",children:[(0,a.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",flexWrap:"wrap",gap:12},children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{className:"pageTitle",children:e("nav.systemLogs")}),(0,a.jsx)("p",{className:"pageDesc",children:"查看 API 异常、模型健康检查失败、PDF 降级等运行时问题。"})]}),(0,a.jsxs)(c.A,{children:[(0,a.jsx)(d.Ay,{icon:(0,a.jsx)(f.A,{}),loading:i,onClick:()=>void N(),children:"刷新"}),(0,a.jsx)(h.A,{title:"确认清空所有错误日志?",onConfirm:()=>{(async()=>{await (0,v.hH)(),n.Ay.success("已清空"),await N()})()},children:(0,a.jsx)(d.Ay,{danger:!0,icon:(0,a.jsx)(y.A,{}),children:"清空日志"})})]})]}),(0,a.jsx)(p.A,{type:"info",showIcon:!0,message:(0,a.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between"},children:[(0,a.jsx)("span",{children:"日志保存在本机 ~/.customize-agent/logs/errors.jsonl,最多读取最近 500 条。"}),(0,a.jsx)(d.Ay,{type:"link",size:"small",icon:I?(0,a.jsx)(m.A,{}):(0,a.jsx)(w.A,{}),onClick:()=>C(!I),style:{padding:"0 4px"},children:I?"收起":"展开"})]}),description:I?"系统自动记录未捕获的异常、API 错误、模型健康检查失败等运行时问题。日志文件超过 2MB 会自动轮转。":void 0}),(0,a.jsx)(g.A.Search,{allowClear:!0,placeholder:"搜索 requestId / source / function / message / stack",value:S,onChange:e=>z(e.target.value),style:{maxWidth:480}}),(0,a.jsx)(u.A,{rowKey:"id",loading:i,dataSource:B,columns:O,size:"middle",locale:{emptyText:(0,a.jsx)(x.A,{description:"暂无错误日志"})},pagination:{pageSize:20,showSizeChanger:!0,showTotal:e=>"共 ".concat(e," 条")},expandable:{expandedRowRender:e=>(0,a.jsxs)("div",{style:{display:"flex",flexDirection:"column",gap:8,padding:"8px 0"},children:[e.request&&(0,a.jsxs)("div",{children:[(0,a.jsx)(A,{strong:!0,style:{fontSize:12,marginBottom:4,display:"block"},children:"Request"}),(0,a.jsx)("pre",{style:{whiteSpace:"pre-wrap",wordBreak:"break-all",margin:0,padding:10,background:"var(--colorFillAlter)",borderRadius:8,fontSize:12,lineHeight:1.5},children:JSON.stringify(e.request,null,2)})]}),void 0!==e.meta&&(0,a.jsxs)("div",{children:[(0,a.jsx)(A,{strong:!0,style:{fontSize:12,marginBottom:4,display:"block"},children:"Meta"}),(0,a.jsx)("pre",{style:{whiteSpace:"pre-wrap",wordBreak:"break-all",margin:0,padding:10,background:"var(--colorFillAlter)",borderRadius:8,fontSize:12,lineHeight:1.5},children:JSON.stringify(e.meta,null,2)})]}),e.stack&&(0,a.jsxs)("div",{children:[(0,a.jsx)(A,{strong:!0,style:{fontSize:12,marginBottom:4,display:"block"},children:"Stack"}),(0,a.jsx)("pre",{style:{whiteSpace:"pre-wrap",wordBreak:"break-all",margin:0,padding:10,background:"var(--colorFillAlter)",borderRadius:8,fontSize:12,lineHeight:1.5,maxHeight:300,overflow:"auto"},children:e.stack})]})]})}})]})}},92123:(e,t)=>{"use strict";t.A={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 00140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"}}]},name:"up",theme:"outlined"}},96651:(e,t,r)=>{"use strict";r.d(t,{A:()=>l});var a=r(97109),s=r(92123),i=r(88483);function n(){return(n=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(e[a]=r[a])}return e}).apply(this,arguments)}let l=a.forwardRef((e,t)=>a.createElement(i.A,n({},e,{ref:t,icon:s.A})))},99811:(e,t,r)=>{"use strict";r.d(t,{A:()=>l});var a=r(97109),s=r(14995),i=r(88483);function n(){return(n=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(e[a]=r[a])}return e}).apply(this,arguments)}let l=a.forwardRef((e,t)=>a.createElement(i.A,n({},e,{ref:t,icon:s.A})))}},e=>{e.O(0,[433,576,195,985,375,102,289,861,636,593,792],()=>e(e.s=39214)),_N_E=e.O()}]);
|
package/messages/en-US.json
CHANGED
|
@@ -16,9 +16,6 @@
|
|
|
16
16
|
"guide": "Guide",
|
|
17
17
|
"models": "Model Config",
|
|
18
18
|
"settings": "Settings",
|
|
19
|
-
"contextEngineering": "Context Engineering",
|
|
20
|
-
"longTermContext": "Long-term Context",
|
|
21
|
-
"shortTermContext": "Short-term Context",
|
|
22
19
|
"promptManagement": "Prompt Management",
|
|
23
20
|
"systemLogs": "System Logs"
|
|
24
21
|
},
|
|
@@ -206,19 +203,6 @@
|
|
|
206
203
|
"save": "Save",
|
|
207
204
|
"cancel": "Cancel"
|
|
208
205
|
},
|
|
209
|
-
"context": {
|
|
210
|
-
"title": "Context Engineering",
|
|
211
|
-
"longTermDesc": "Persistent context from memory store (cross-session)",
|
|
212
|
-
"shortTermDesc": "Short-term context from recent session logs",
|
|
213
|
-
"longTermSource": "Source: ~/.customize-agent/memory.db (Memory Store)",
|
|
214
|
-
"shortTermSource": "Source: ~/.customize-agent/logs/ (Session Logs)",
|
|
215
|
-
"importance": "Importance",
|
|
216
|
-
"content": "Content",
|
|
217
|
-
"tags": "Tags",
|
|
218
|
-
"source": "Source",
|
|
219
|
-
"sourceHint": "Optional additional source/context description",
|
|
220
|
-
"updatedAt": "Updated"
|
|
221
|
-
},
|
|
222
206
|
"prompt": {
|
|
223
207
|
"title": "Prompt Management",
|
|
224
208
|
"description": "Manage CUSTOMIZE.md system prompt files per project",
|
package/messages/zh-CN.json
CHANGED
|
@@ -16,9 +16,6 @@
|
|
|
16
16
|
"guide": "指引",
|
|
17
17
|
"models": "模型配置",
|
|
18
18
|
"settings": "设置",
|
|
19
|
-
"contextEngineering": "上下文工程",
|
|
20
|
-
"longTermContext": "长期上下文",
|
|
21
|
-
"shortTermContext": "短期上下文",
|
|
22
19
|
"promptManagement": "提示词管理",
|
|
23
20
|
"systemLogs": "系统日志"
|
|
24
21
|
},
|
|
@@ -206,19 +203,6 @@
|
|
|
206
203
|
"save": "保存",
|
|
207
204
|
"cancel": "取消"
|
|
208
205
|
},
|
|
209
|
-
"context": {
|
|
210
|
-
"title": "上下文工程管理",
|
|
211
|
-
"longTermDesc": "来自记忆库的持久化上下文(跨会话保留)",
|
|
212
|
-
"shortTermDesc": "来自最近会话日志的短期上下文",
|
|
213
|
-
"longTermSource": "数据来源: ~/.customize-agent/memory.db(记忆库)",
|
|
214
|
-
"shortTermSource": "数据来源: ~/.customize-agent/logs/(会话日志)",
|
|
215
|
-
"importance": "重要性",
|
|
216
|
-
"content": "内容",
|
|
217
|
-
"tags": "标签",
|
|
218
|
-
"source": "来源",
|
|
219
|
-
"sourceHint": "可选,额外的来源/上下文说明",
|
|
220
|
-
"updatedAt": "更新时间"
|
|
221
|
-
},
|
|
222
206
|
"prompt": {
|
|
223
207
|
"title": "提示词管理",
|
|
224
208
|
"description": "管理各项目的 CUSTOMIZE.md 系统提示词文件",
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@customize-agent/server",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.95",
|
|
4
4
|
"description": "Customize Agent Web 管理控制台",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./package.json": "./package.json"
|
|
7
7
|
},
|
|
8
|
+
"bin": {
|
|
9
|
+
"customize-web": "scripts/start-server.cjs",
|
|
10
|
+
"customize-dashboard": "scripts/start-server.cjs"
|
|
11
|
+
},
|
|
8
12
|
"files": [
|
|
9
13
|
".next/BUILD_ID",
|
|
10
14
|
".next/app-build-manifest.json",
|
|
@@ -50,9 +54,9 @@
|
|
|
50
54
|
"tesseract.js": "^7.0.0",
|
|
51
55
|
"typescript": "^6.0.3",
|
|
52
56
|
"xlsx": "^0.18.5",
|
|
53
|
-
"@customize-agent/
|
|
54
|
-
"@customize-agent/
|
|
55
|
-
"@customize-agent/
|
|
57
|
+
"@customize-agent/knowledge": "^4.0.37",
|
|
58
|
+
"@customize-agent/llm": "^3.0.10",
|
|
59
|
+
"@customize-agent/runtime": "^3.0.10"
|
|
56
60
|
},
|
|
57
61
|
"devDependencies": {
|
|
58
62
|
"@tailwindcss/postcss": "^4.3.2",
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { spawnSync } = require('child_process');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const serverRoot = path.resolve(__dirname, '..');
|
|
7
|
+
const originalCwd = process.cwd();
|
|
8
|
+
|
|
9
|
+
function readOption(names, fallback) {
|
|
10
|
+
for (let i = 0; i < process.argv.length; i += 1) {
|
|
11
|
+
const arg = process.argv[i];
|
|
12
|
+
const matched = names.find(name => arg === name || arg.startsWith(`${name}=`));
|
|
13
|
+
if (!matched) continue;
|
|
14
|
+
if (arg.includes('=')) return arg.slice(arg.indexOf('=') + 1);
|
|
15
|
+
return process.argv[i + 1] || fallback;
|
|
16
|
+
}
|
|
17
|
+
return fallback;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
21
|
+
console.log(`Usage: customize-web [--port 17321] [--host 127.0.0.1] [--project /path/to/project]
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
-p, --port Web server port, default 17321
|
|
25
|
+
-H, --host Web server host, default 127.0.0.1
|
|
26
|
+
--project Project root managed by the dashboard, default current directory
|
|
27
|
+
|
|
28
|
+
Environment:
|
|
29
|
+
CUSTOMIZE_PROJECT_ROOT Project root managed by the dashboard
|
|
30
|
+
PORT Web server port
|
|
31
|
+
HOST Web server host`);
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const port = readOption(['--port', '-p'], process.env.PORT || process.env.CUSTOMIZE_WEB_PORT || '17321');
|
|
36
|
+
const host = readOption(['--host', '-H'], process.env.HOST || process.env.CUSTOMIZE_WEB_HOST || '127.0.0.1');
|
|
37
|
+
const projectRoot = path.resolve(readOption(['--project'], process.env.CUSTOMIZE_PROJECT_ROOT || originalCwd));
|
|
38
|
+
const buildIdPath = path.join(serverRoot, '.next', 'BUILD_ID');
|
|
39
|
+
|
|
40
|
+
if (!fs.existsSync(buildIdPath)) {
|
|
41
|
+
console.error('[customize-web] Missing production build artifacts. Reinstall @customize-agent/server or run its build step before starting.');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const verify = spawnSync(process.execPath, [path.join(serverRoot, 'scripts', 'verify-next-static.js')], {
|
|
46
|
+
cwd: serverRoot,
|
|
47
|
+
stdio: 'inherit',
|
|
48
|
+
env: process.env,
|
|
49
|
+
});
|
|
50
|
+
if (verify.status !== 0) process.exit(verify.status || 1);
|
|
51
|
+
|
|
52
|
+
let nextBin;
|
|
53
|
+
try {
|
|
54
|
+
nextBin = require.resolve('next/dist/bin/next', { paths: [serverRoot] });
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error('[customize-web] Unable to resolve Next.js runtime from @customize-agent/server.');
|
|
57
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log(`[customize-web] Project root: ${projectRoot}`);
|
|
62
|
+
console.log(`[customize-web] Starting: http://${host}:${port}/overview`);
|
|
63
|
+
|
|
64
|
+
const result = spawnSync(process.execPath, [nextBin, 'start', '-p', String(port), '-H', String(host)], {
|
|
65
|
+
cwd: serverRoot,
|
|
66
|
+
stdio: 'inherit',
|
|
67
|
+
env: {
|
|
68
|
+
...process.env,
|
|
69
|
+
NODE_ENV: 'production',
|
|
70
|
+
CUSTOMIZE_PROJECT_ROOT: projectRoot,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (result.error) {
|
|
75
|
+
console.error('[customize-web] Failed to start dashboard.');
|
|
76
|
+
console.error(result.error.message);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
process.exit(result.status ?? 0);
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
|
|
5
|
+
const packageRoot = path.resolve(process.argv[2] || process.env.PACKAGE_ROOT || '.');
|
|
6
|
+
const installRoot = path.resolve(packageRoot, '..', '..');
|
|
7
|
+
const node = process.execPath;
|
|
8
|
+
const packageJsonPath = path.join(packageRoot, 'package.json');
|
|
9
|
+
const packageJson = fs.existsSync(packageJsonPath) ? JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) : null;
|
|
10
|
+
const serverRoot = packageJson?.name === '@customize-agent/server'
|
|
11
|
+
? packageRoot
|
|
12
|
+
: path.dirname(require.resolve('@customize-agent/server/package.json', { paths: [packageRoot, installRoot] }));
|
|
13
|
+
const nextBin = require.resolve('next/dist/bin/next', { paths: [serverRoot, packageRoot, installRoot] });
|
|
14
|
+
const tempRoot = process.env.RUNNER_TEMP || fs.mkdtempSync(path.join(require('os').tmpdir(), 'customize-upload-'));
|
|
15
|
+
const home = path.join(tempRoot, 'upload-home');
|
|
16
|
+
const projectRoot = path.join(tempRoot, 'upload-project');
|
|
17
|
+
const dashboardLog = path.join(tempRoot, 'upload-dashboard.log');
|
|
18
|
+
const basePort = 18000 + Math.floor(Math.random() * 1000);
|
|
19
|
+
const port = Number(process.env.CUSTOMIZE_UPLOAD_PORT || basePort);
|
|
20
|
+
const base = `http://127.0.0.1:${port}`;
|
|
21
|
+
const marker = `uploadmatrix${Date.now()}`;
|
|
22
|
+
|
|
23
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
24
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
25
|
+
fs.rmSync(dashboardLog, { force: true });
|
|
26
|
+
fs.mkdirSync(projectRoot, { recursive: true });
|
|
27
|
+
|
|
28
|
+
function minimalPng() {
|
|
29
|
+
return Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', 'base64');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function minimalPdf(text) {
|
|
33
|
+
const stream = `BT /F1 12 Tf 72 720 Td (${text.replace(/[()\\]/g, ' ')}) Tj ET`;
|
|
34
|
+
const objs = [
|
|
35
|
+
'1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj',
|
|
36
|
+
'2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj',
|
|
37
|
+
'3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >> endobj',
|
|
38
|
+
'4 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> endobj',
|
|
39
|
+
`5 0 obj << /Length ${Buffer.byteLength(stream)} >> stream\n${stream}\nendstream endobj`,
|
|
40
|
+
];
|
|
41
|
+
let out = '%PDF-1.4\n';
|
|
42
|
+
const offsets = [0];
|
|
43
|
+
for (const obj of objs) { offsets.push(Buffer.byteLength(out)); out += obj + '\n'; }
|
|
44
|
+
const xref = Buffer.byteLength(out);
|
|
45
|
+
out += `xref\n0 ${objs.length + 1}\n0000000000 65535 f \n`;
|
|
46
|
+
for (let i = 1; i < offsets.length; i++) out += String(offsets[i]).padStart(10, '0') + ' 00000 n \n';
|
|
47
|
+
out += `trailer << /Size ${objs.length + 1} /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF`;
|
|
48
|
+
return Buffer.from(out);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const text = kind => `${marker} ${kind} searchable content`;
|
|
52
|
+
const samples = [
|
|
53
|
+
{ name: 'doc-plain.txt', kind: 'document/plaintext', content: text('txt') },
|
|
54
|
+
{ name: 'doc-markdown.md', kind: 'document/markdown', content: `# ${text('markdown')}\n` },
|
|
55
|
+
{ name: 'doc-pdf.pdf', kind: 'document/pdf', content: minimalPdf(text('pdf')), searchable: false },
|
|
56
|
+
{ name: 'sheet-csv.csv', kind: 'spreadsheet/csv', content: `name,value\n${marker},csv\n` },
|
|
57
|
+
{ name: 'sheet-tsv.tsv', kind: 'spreadsheet/tsv', content: `name\tvalue\n${marker}\ttsv\n` },
|
|
58
|
+
{ name: 'image-svg.svg', kind: 'image/vector', content: `<svg xmlns="http://www.w3.org/2000/svg"><text>${text('svg')}</text></svg>` },
|
|
59
|
+
{ name: 'image-png.png', kind: 'image/raster', content: minimalPng(), allowZeroChunks: true },
|
|
60
|
+
{ name: 'cad-dxf.dxf', kind: 'cad/autocad', content: `0\nSECTION\n2\nENTITIES\n0\nTEXT\n1\n${text('dxf')}\n0\nENDSEC\n0\nEOF\n` },
|
|
61
|
+
{ name: 'cad-step.step', kind: 'cad/step', content: `ISO-10303-21; HEADER; FILE_DESCRIPTION(('${text('step')}'),'2;1'); ENDSEC; DATA; ENDSEC; END-ISO-10303-21;` },
|
|
62
|
+
{ name: 'code-js.js', kind: 'code/javascript', content: `export const marker = '${text('javascript')}';\n` },
|
|
63
|
+
{ name: 'code-py.py', kind: 'code/python', content: `marker = '${text('python')}'\n` },
|
|
64
|
+
{ name: 'data-json.json', kind: 'data/json', content: JSON.stringify({ marker, type: 'json', text: text('json') }) },
|
|
65
|
+
{ name: 'data-yaml.yaml', kind: 'data/yaml', content: `marker: ${marker}\ntext: ${text('yaml')}\n` },
|
|
66
|
+
{ name: 'web-html.html', kind: 'web/html', content: `<html><body>${text('html')}</body></html>` },
|
|
67
|
+
{ name: 'web-css.css', kind: 'web/stylesheet', content: `/* ${text('css')} */\nbody{color:#111}` },
|
|
68
|
+
{ name: 'diagram-drawio.drawio', kind: 'diagram/drawio', content: `<mxfile><diagram>${text('drawio')}</diagram></mxfile>`, searchable: false },
|
|
69
|
+
{ name: 'diagram-mermaid.mmd', kind: 'diagram/mermaid', content: `graph TD\nA[${text('mermaid')}] --> B` },
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
async function request(method, url, body, timeoutMs = 30000) {
|
|
73
|
+
const init = { method, signal: AbortSignal.timeout(timeoutMs) };
|
|
74
|
+
if (body !== undefined) {
|
|
75
|
+
init.headers = { 'content-type': 'application/json' };
|
|
76
|
+
init.body = JSON.stringify(body);
|
|
77
|
+
}
|
|
78
|
+
const res = await fetch(url, init);
|
|
79
|
+
const raw = await res.text();
|
|
80
|
+
let json;
|
|
81
|
+
try { json = JSON.parse(raw); } catch { json = raw; }
|
|
82
|
+
return { status: res.status, json, raw };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function uploadSample(baseUrl, root, sample, uploadId) {
|
|
86
|
+
const form = new FormData();
|
|
87
|
+
form.append('uploadId', uploadId);
|
|
88
|
+
form.append('projectRoot', root);
|
|
89
|
+
form.append('relativePaths', sample.name);
|
|
90
|
+
form.append('batchIndex', '0');
|
|
91
|
+
form.append('totalBatches', '1');
|
|
92
|
+
form.append('startIndex', '1');
|
|
93
|
+
form.append('uploadComplete', '1');
|
|
94
|
+
form.append('fileOffset', '0');
|
|
95
|
+
form.append('files', new Blob([sample.content]), sample.name);
|
|
96
|
+
const res = await fetch(`${baseUrl}/api/kb/upload`, { method: 'POST', body: form, signal: AbortSignal.timeout(30000) });
|
|
97
|
+
const raw = await res.text();
|
|
98
|
+
let json;
|
|
99
|
+
try { json = JSON.parse(raw); } catch { json = raw; }
|
|
100
|
+
return { status: res.status, json, raw };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function waitFor(label, fn, timeoutMs = 120000) {
|
|
104
|
+
const deadline = Date.now() + timeoutMs;
|
|
105
|
+
let last;
|
|
106
|
+
while (Date.now() < deadline) {
|
|
107
|
+
try {
|
|
108
|
+
const result = await fn();
|
|
109
|
+
if (result) return result;
|
|
110
|
+
} catch (error) {
|
|
111
|
+
last = error;
|
|
112
|
+
}
|
|
113
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
114
|
+
}
|
|
115
|
+
throw new Error(`${label} timeout${last ? `: ${last.message || last}` : ''}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function assert(ok, message) {
|
|
119
|
+
if (!ok) throw new Error(message);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function indexedDetail(detail, allowZeroChunks = false) {
|
|
123
|
+
const file = detail.json?.file;
|
|
124
|
+
return file && file.status !== 'pending' && Number(file.indexedAt) > 0 && (allowZeroChunks || Number(file.chunkCount) > 0);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function searchHasHit(search, relativePath, expectedText) {
|
|
128
|
+
return Array.isArray(search.json?.results) && search.json.results.some(result => {
|
|
129
|
+
const filePath = result.filePath || result.relativePath;
|
|
130
|
+
return filePath === relativePath && (!expectedText || String(result.content || '').includes(expectedText));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function startServer(serverPort, root, logPath) {
|
|
135
|
+
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
136
|
+
const out = fs.openSync(logPath, 'a');
|
|
137
|
+
const child = spawn(node, [nextBin, 'start', '-p', String(serverPort), '-H', '127.0.0.1'], {
|
|
138
|
+
cwd: serverRoot,
|
|
139
|
+
stdio: ['ignore', out, out],
|
|
140
|
+
env: { ...process.env, HOME: home, CUSTOMIZE_AGENT_HOME: home, NODE_ENV: 'production', CUSTOMIZE_PROJECT_ROOT: root, CUSTOMIZE_AGENT_DISABLE_OCR: '1', LOG_LEVEL: 'debug' },
|
|
141
|
+
});
|
|
142
|
+
fs.closeSync(out);
|
|
143
|
+
await waitFor(`dashboard ${serverPort}`, async () => {
|
|
144
|
+
const health = await request('GET', `http://127.0.0.1:${serverPort}/api/health`);
|
|
145
|
+
return health.status < 500 ? true : undefined;
|
|
146
|
+
}, 120000);
|
|
147
|
+
return child;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function dumpEnv() {
|
|
151
|
+
console.error('ENV:', {
|
|
152
|
+
NODE_VERSION: process.version,
|
|
153
|
+
packageRoot,
|
|
154
|
+
serverRoot,
|
|
155
|
+
nextBin,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const pages = ['/', '/overview', '/knowledge', '/knowledge/files', '/knowledge/manage', '/knowledge/search', '/models', '/prompt', '/settings'];
|
|
160
|
+
const apiChecks = [
|
|
161
|
+
{ method: 'GET', path: '/api/health' },
|
|
162
|
+
{ method: 'GET', path: '/api/config/models' },
|
|
163
|
+
{ method: 'GET', path: '/api/config/providers' },
|
|
164
|
+
{ method: 'GET', path: '/api/kb/features' },
|
|
165
|
+
{ method: 'GET', path: '/api/kb/categories' },
|
|
166
|
+
{ method: 'GET', path: '/api/kb/tags' },
|
|
167
|
+
{ method: 'GET', path: '/api/kb/files', query: root => `projectRoot=${encodeURIComponent(root)}&limit=10` },
|
|
168
|
+
{ method: 'GET', path: '/api/kb/stats', query: root => `projectRoot=${encodeURIComponent(root)}` },
|
|
169
|
+
{ method: 'GET', path: '/api/kb/search', query: root => `projectRoot=${encodeURIComponent(root)}&q=${encodeURIComponent(marker)}&limit=5` },
|
|
170
|
+
{ method: 'GET', path: '/api/kb/duplicates', query: root => `projectRoot=${encodeURIComponent(root)}` },
|
|
171
|
+
{ method: 'GET', path: '/api/kb/operations', query: root => `projectRoot=${encodeURIComponent(root)}` },
|
|
172
|
+
{ method: 'GET', path: '/api/prompt' },
|
|
173
|
+
{ method: 'GET', path: '/api/system/stats' },
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
async function verifyWebSurface(baseUrl, root, label) {
|
|
177
|
+
for (const page of pages) {
|
|
178
|
+
const res = await request('GET', `${baseUrl}${page}`);
|
|
179
|
+
assert(res.status >= 200 && res.status < 400, `${label} page ${page} failed: ${res.status} ${res.raw.slice(0, 300)}`);
|
|
180
|
+
}
|
|
181
|
+
for (const api of apiChecks) {
|
|
182
|
+
const query = api.query ? `?${api.query(root)}` : '';
|
|
183
|
+
const res = await request(api.method, `${baseUrl}${api.path}${query}`);
|
|
184
|
+
assert(res.status >= 200 && res.status < 300, `${label} api ${api.path} failed: ${res.status} ${res.raw.slice(0, 500)}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
(async () => {
|
|
189
|
+
assert(fs.existsSync(path.join(serverRoot, '.next', 'BUILD_ID')), `dashboard build not found: ${serverRoot}`);
|
|
190
|
+
|
|
191
|
+
let dashboardPid;
|
|
192
|
+
try {
|
|
193
|
+
const dashboard = await startServer(port, projectRoot, dashboardLog);
|
|
194
|
+
dashboardPid = dashboard.pid;
|
|
195
|
+
await verifyWebSurface(base, projectRoot, 'direct dashboard');
|
|
196
|
+
|
|
197
|
+
for (let i = 0; i < samples.length; i++) {
|
|
198
|
+
const sample = samples[i];
|
|
199
|
+
const uploadId = `upload-matrix-${i}-${Date.now()}`;
|
|
200
|
+
const res = await uploadSample(base, projectRoot, sample, uploadId);
|
|
201
|
+
assert(res.status === 202 && res.json.success, `${sample.name} upload failed: ${res.status} ${res.raw}`);
|
|
202
|
+
const relativePath = res.json.relativePath;
|
|
203
|
+
assert(relativePath, `${sample.name} missing relativePath`);
|
|
204
|
+
const progress = await request('GET', `${base}/api/kb/upload/progress?id=${encodeURIComponent(uploadId)}`);
|
|
205
|
+
assert(progress.status === 200, `${sample.name} progress failed: ${progress.status} ${progress.raw}`);
|
|
206
|
+
const files = await request('GET', `${base}/api/kb/files?projectRoot=${encodeURIComponent(projectRoot)}&limit=500`);
|
|
207
|
+
assert(files.status === 200, `${sample.name} files failed: ${files.status} ${files.raw}`);
|
|
208
|
+
assert(files.json.files?.some(f => f.relativePath === relativePath), `${sample.name} not listed`);
|
|
209
|
+
const reindex = await request('POST', `${base}/api/kb/files/reindex`, { projectRoot, relativePath });
|
|
210
|
+
assert(reindex.status === 200 || reindex.status === 202, `${sample.name} reindex failed: ${reindex.status} ${reindex.raw}`);
|
|
211
|
+
const detail = await waitFor(`${sample.name} indexed detail`, async () => {
|
|
212
|
+
const current = await request('GET', `${base}/api/kb/files/detail?projectRoot=${encodeURIComponent(projectRoot)}&relativePath=${encodeURIComponent(relativePath)}`);
|
|
213
|
+
if (current.status !== 200) throw new Error(`${sample.name} detail failed: ${current.status} ${current.raw}`);
|
|
214
|
+
if (current.json.file?.relativePath !== relativePath) throw new Error(`${sample.name} detail mismatch`);
|
|
215
|
+
return indexedDetail(current, sample.allowZeroChunks) ? current : undefined;
|
|
216
|
+
}, 120000);
|
|
217
|
+
if (!sample.allowZeroChunks && sample.searchable !== false) {
|
|
218
|
+
const search = await waitFor(`${sample.name} searchable marker`, async () => {
|
|
219
|
+
const current = await request('GET', `${base}/api/kb/search?projectRoot=${encodeURIComponent(projectRoot)}&q=${encodeURIComponent(marker)}&limit=50&vectorWeight=1&rewriteWeight=0&keywordWeight=1`);
|
|
220
|
+
if (current.status !== 200) throw new Error(`${sample.name} search failed: ${current.status} ${current.raw}`);
|
|
221
|
+
return searchHasHit(current, relativePath, marker) ? current : undefined;
|
|
222
|
+
}, 120000);
|
|
223
|
+
assert(searchHasHit(search, relativePath, marker), `${sample.name} search did not include marker hit`);
|
|
224
|
+
}
|
|
225
|
+
console.log('UPLOAD', sample.kind, sample.name, JSON.stringify({ relativePath, chunks: detail.json.file?.chunkCount, vector: res.json.vectorStatus?.status }));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const incrementalPath = path.join(projectRoot, 'knowledgeBase', '文档资料', 'incremental-local.txt');
|
|
229
|
+
fs.mkdirSync(path.dirname(incrementalPath), { recursive: true });
|
|
230
|
+
fs.writeFileSync(incrementalPath, text('incremental-local'));
|
|
231
|
+
const reindexAll = await request('POST', `${base}/api/kb/reindex`, { projectRoot });
|
|
232
|
+
assert((reindexAll.status === 200 || reindexAll.status === 202) && reindexAll.json.success, `incremental reindex failed: ${reindexAll.status} ${reindexAll.raw}`);
|
|
233
|
+
if (reindexAll.status === 200) assert(Number(reindexAll.json.diff?.newFiles) >= 1, `incremental reindex did not detect new file: ${reindexAll.raw}`);
|
|
234
|
+
const incrementalDetail = await waitFor('incremental indexed detail', async () => {
|
|
235
|
+
const current = await request('GET', `${base}/api/kb/files/detail?projectRoot=${encodeURIComponent(projectRoot)}&relativePath=${encodeURIComponent('文档资料/incremental-local.txt')}`);
|
|
236
|
+
if (current.status !== 200) throw new Error(`incremental detail failed: ${current.status} ${current.raw}`);
|
|
237
|
+
return indexedDetail(current) ? current : undefined;
|
|
238
|
+
}, 120000);
|
|
239
|
+
assert(Number(incrementalDetail.json.file?.chunkCount) > 0, 'incremental file was not parsed/chunked');
|
|
240
|
+
|
|
241
|
+
const readyStats = await waitFor('HNSWLib vector index', async () => {
|
|
242
|
+
const stats = await request('GET', `${base}/api/kb/stats?projectRoot=${encodeURIComponent(projectRoot)}`);
|
|
243
|
+
if (stats.status !== 200) throw new Error(`stats ${stats.status} ${stats.raw}`);
|
|
244
|
+
const vector = stats.json.vectorStatus;
|
|
245
|
+
if (vector?.status === 'ready' && Number(vector.indexedChunks) >= Number(stats.json.chunkCount) && Number(stats.json.chunkCount) > 0) return stats.json;
|
|
246
|
+
return undefined;
|
|
247
|
+
}, 180000);
|
|
248
|
+
console.log('UPLOAD_VECTOR_MATRIX_OK', JSON.stringify({ files: samples.length, marker, projectRoot, chunkCount: readyStats.chunkCount, indexedChunks: readyStats.vectorStatus.indexedChunks }));
|
|
249
|
+
process.exitCode = 0;
|
|
250
|
+
} finally {
|
|
251
|
+
if (dashboardPid) { try { process.kill(dashboardPid); } catch {} }
|
|
252
|
+
}
|
|
253
|
+
})().catch(error => {
|
|
254
|
+
process.exitCode = 1;
|
|
255
|
+
console.error(error.stack || String(error));
|
|
256
|
+
dumpEnv();
|
|
257
|
+
if (fs.existsSync(dashboardLog)) console.error(fs.readFileSync(dashboardLog, 'utf8'));
|
|
258
|
+
}).finally(() => process.exit(process.exitCode ?? 0));
|