@customize-agent/server 4.60.6 → 4.60.11

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 (53) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/prerender-manifest.json +3 -3
  4. package/.next/required-server-files.json +1 -1
  5. package/.next/server/chunks/1001.js +1 -1
  6. package/.next/server/chunks/1243.js +1 -1
  7. package/.next/server/chunks/2328.js +1 -1
  8. package/.next/server/chunks/3806.js +1 -1
  9. package/.next/server/chunks/{7848.js → 4722.js} +65 -65
  10. package/.next/server/chunks/8204.js +1 -1
  11. package/.next/server/chunks/9666.js +76 -76
  12. package/.next/server/instrumentation.js +1 -1
  13. package/.next/server/instrumentation.js.nft.json +1 -1
  14. package/.next/server/middleware-build-manifest.js +1 -1
  15. package/.next/server/pages/404.html +1 -1
  16. package/.next/server/pages/500.html +1 -1
  17. package/.next/server/pages/api/documents/export.js +1 -1
  18. package/.next/server/pages/api/documents/generate/preview.js +1 -1
  19. package/.next/server/pages/api/documents/generate.js +1 -1
  20. package/.next/server/pages/api/documents/generated/[id]/instruction.js +1 -1
  21. package/.next/server/pages/api/documents/generated/[id]/pause.js +1 -1
  22. package/.next/server/pages/api/health.js +1 -1
  23. package/.next/server/pages/api/kb/upload.js +2 -2
  24. package/.next/server/pages/api/system/data-health.js +1 -1
  25. package/.next/server/pages/canvas/[id].html +1 -1
  26. package/.next/server/pages/canvas.html +1 -1
  27. package/.next/server/pages/documents.html +1 -1
  28. package/.next/server/pages/guide.html +1 -1
  29. package/.next/server/pages/index.html +1 -1
  30. package/.next/server/pages/knowledge/file-detail.html +1 -1
  31. package/.next/server/pages/knowledge/files.html +1 -1
  32. package/.next/server/pages/knowledge/manage.html +1 -1
  33. package/.next/server/pages/knowledge/source-preview.html +1 -1
  34. package/.next/server/pages/knowledge.html +1 -1
  35. package/.next/server/pages/models.html +1 -1
  36. package/.next/server/pages/overview.html +1 -1
  37. package/.next/server/pages/prompt.html +1 -1
  38. package/.next/server/pages/settings.html +1 -1
  39. package/.next/server/pages/skills/[id]/edit.html +1 -1
  40. package/.next/server/pages/skills/[id].html +1 -1
  41. package/.next/server/pages/skills/new.html +1 -1
  42. package/.next/server/pages/skills.html +1 -1
  43. package/.next/server/pages/system/logs.html +1 -1
  44. package/.next/server/pages-manifest.json +31 -31
  45. package/.next/static/chunks/pages/{_app-3f5aa4ff7951feca.js → _app-28228d95968c4d44.js} +1 -1
  46. package/package.json +2 -2
  47. package/scripts/capture-baseline.mjs +4 -2
  48. package/scripts/half-built-scan.allow.json +1 -1
  49. package/scripts/kb-index-worker.cjs +2 -2
  50. package/scripts/kb-worker-ipc.cjs +1 -1
  51. package/scripts/upload-matrix.cjs +44 -25
  52. /package/.next/static/{3a50a07d5e578847f7a1eefe9573b36527d6e1f5a7d0cb3b4883423ccfabc75b → 36956db6655c7ce7a67c9b6862b2ca1b6b5308f268b5595d430facff6c0f4152}/_buildManifest.js +0 -0
  53. /package/.next/static/{3a50a07d5e578847f7a1eefe9573b36527d6e1f5a7d0cb3b4883423ccfabc75b → 36956db6655c7ce7a67c9b6862b2ca1b6b5308f268b5595d430facff6c0f4152}/_ssgManifest.js +0 -0
@@ -12,7 +12,7 @@ const serverRoot = packageJson?.name === '@customize-agent/server'
12
12
  : path.dirname(require.resolve('@customize-agent/server/package.json', { paths: [packageRoot, installRoot] }));
13
13
  const nextBin = require.resolve('next/dist/bin/next', { paths: [serverRoot, packageRoot, installRoot] });
14
14
  const tempRoot = process.env.RUNNER_TEMP || fs.mkdtempSync(path.join(require('os').tmpdir(), 'customize-upload-'));
15
- const home = path.join(tempRoot, 'upload-home');
15
+ const uploadDataHome = path.join(tempRoot, 'upload-home');
16
16
  const projectRoot = path.join(tempRoot, 'upload-project');
17
17
  const dashboardLog = path.join(tempRoot, 'upload-dashboard.log');
18
18
  const basePort = 18000 + Math.floor(Math.random() * 1000);
@@ -20,7 +20,7 @@ const port = Number(process.env.CUSTOMIZE_UPLOAD_PORT || basePort);
20
20
  const base = `http://127.0.0.1:${port}`;
21
21
  const marker = `uploadmatrix${Date.now()}`;
22
22
 
23
- fs.rmSync(home, { recursive: true, force: true });
23
+ fs.rmSync(uploadDataHome, { recursive: true, force: true });
24
24
  fs.rmSync(projectRoot, { recursive: true, force: true });
25
25
  fs.rmSync(dashboardLog, { force: true });
26
26
  fs.mkdirSync(projectRoot, { recursive: true });
@@ -29,6 +29,19 @@ function minimalPng() {
29
29
  return Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', 'base64');
30
30
  }
31
31
 
32
+ function ocrPng() {
33
+ const canvasModule = require(require.resolve('@napi-rs/canvas', { paths: [serverRoot] }));
34
+ const font = path.join(serverRoot, 'public', 'fonts', 'NotoSansCJKsc-Regular.otf');
35
+ assert(fs.existsSync(font), 'Packaged review font is missing');
36
+ canvasModule.GlobalFonts.registerFromPath(font, 'UploadFixtureFont');
37
+ const canvas = canvasModule.createCanvas(1200, 240), context = canvas.getContext('2d');
38
+ context.fillStyle = '#fff'; context.fillRect(0, 0, 1200, 240);
39
+ context.fillStyle = '#000'; context.font = '44px UploadFixtureFont';
40
+ context.fillText('混凝土强度等级 C35', 30, 75);
41
+ context.fillText('合同工期 180 日历天', 30, 165);
42
+ return canvas.toBuffer('image/png');
43
+ }
44
+
32
45
  function minimalPdf(text) {
33
46
  const stream = `BT /F1 12 Tf 72 720 Td (${text.replace(/[()\\]/g, ' ')}) Tj ET`;
34
47
  const objs = [
@@ -57,6 +70,7 @@ const samples = [
57
70
  { name: 'sheet-tsv.tsv', kind: 'spreadsheet/tsv', content: `name\tvalue\n${marker}\ttsv\n` },
58
71
  { name: 'image-svg.svg', kind: 'image/vector', content: `<svg xmlns="http://www.w3.org/2000/svg"><text>${text('svg')}</text></svg>` },
59
72
  { name: 'image-png.png', kind: 'image/raster', content: minimalPng(), allowZeroChunks: true },
73
+ { name: 'image-ocr.png', kind: 'image/raster-ocr', content: ocrPng(), expectedText: 'C35', additionalText: '180', query: '混凝土 C35 工期 180' },
60
74
  { name: 'cad-dxf.dxf', kind: 'cad/autocad', content: `0\nSECTION\n2\nENTITIES\n0\nTEXT\n1\n${text('dxf')}\n0\nENDSEC\n0\nEOF\n` },
61
75
  { 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
76
  { name: 'code-js.js', kind: 'code/javascript', content: `export const marker = '${text('javascript')}';\n` },
@@ -65,7 +79,7 @@ const samples = [
65
79
  { name: 'data-yaml.yaml', kind: 'data/yaml', content: `marker: ${marker}\ntext: ${text('yaml')}\n` },
66
80
  { name: 'web-html.html', kind: 'web/html', content: `<html><body>${text('html')}</body></html>` },
67
81
  { 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 },
82
+ { name: 'diagram-drawio.drawio', kind: 'diagram/drawio', content: `<mxfile><diagram><mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" parent="1" vertex="1" value="${text('drawio')}"><mxGeometry x="10" y="10" width="100" height="40" as="geometry"/></mxCell></root></mxGraphModel></diagram></mxfile>` },
69
83
  { name: 'diagram-mermaid.mmd', kind: 'diagram/mermaid', content: `graph TD\nA[${text('mermaid')}] --> B` },
70
84
  ];
71
85
 
@@ -86,13 +100,13 @@ async function uploadSample(baseUrl, root, sample, uploadId) {
86
100
  const form = new FormData();
87
101
  form.append('uploadId', uploadId);
88
102
  form.append('projectRoot', root);
89
- form.append('relativePaths', sample.name);
103
+ form.append('relativePaths[0]', sample.name);
90
104
  form.append('batchIndex', '0');
91
105
  form.append('totalBatches', '1');
92
106
  form.append('startIndex', '1');
93
107
  form.append('uploadComplete', '1');
94
108
  form.append('fileOffset', '0');
95
- form.append('files', new Blob([sample.content]), sample.name);
109
+ form.append('files[0]', new Blob([sample.content]), sample.name);
96
110
  const res = await fetch(`${baseUrl}/api/kb/upload`, { method: 'POST', body: form, signal: AbortSignal.timeout(30000) });
97
111
  const raw = await res.text();
98
112
  let json;
@@ -124,11 +138,9 @@ function indexedDetail(detail, allowZeroChunks = false) {
124
138
  return file && file.status !== 'pending' && Number(file.indexedAt) > 0 && (allowZeroChunks || Number(file.chunkCount) > 0);
125
139
  }
126
140
 
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
- });
141
+ function searchHasHit(search, relativePath) {
142
+ return search.json?.contentSearchStatus === 'success' && !search.json.failures?.length
143
+ && search.json.files?.some(result => result.relativePath === relativePath && result.matchedBy === 'content');
132
144
  }
133
145
 
134
146
  async function startServer(serverPort, root, logPath) {
@@ -137,12 +149,12 @@ async function startServer(serverPort, root, logPath) {
137
149
  const child = spawn(node, [nextBin, 'start', '-p', String(serverPort), '-H', '127.0.0.1'], {
138
150
  cwd: serverRoot,
139
151
  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' },
152
+ env: { ...process.env, CUSTOMIZE_AGENT_HOME: uploadDataHome, CUSTOMIZE_EMBEDDING_PROVIDER: 'transformers-local', NODE_ENV: 'production', CUSTOMIZE_PROJECT_ROOT: root, LOG_LEVEL: 'debug' },
141
153
  });
142
154
  fs.closeSync(out);
143
155
  await waitFor(`dashboard ${serverPort}`, async () => {
144
156
  const health = await request('GET', `http://127.0.0.1:${serverPort}/api/health`);
145
- return health.status < 500 ? true : undefined;
157
+ return health.status === 200 && health.json?.status === 'ok' ? true : undefined;
146
158
  }, 120000);
147
159
  return child;
148
160
  }
@@ -156,7 +168,7 @@ function dumpEnv() {
156
168
  });
157
169
  }
158
170
 
159
- const pages = ['/', '/overview', '/knowledge', '/knowledge/files', '/knowledge/manage', '/knowledge/search', '/models', '/prompt', '/settings'];
171
+ const pages = ['/', '/overview', '/knowledge', '/knowledge/files', '/knowledge/manage', '/models', '/prompt', '/settings'];
160
172
  const apiChecks = [
161
173
  { method: 'GET', path: '/api/health' },
162
174
  { method: 'GET', path: '/api/config/models' },
@@ -166,7 +178,7 @@ const apiChecks = [
166
178
  { method: 'GET', path: '/api/kb/tags' },
167
179
  { method: 'GET', path: '/api/kb/files', query: root => `projectRoot=${encodeURIComponent(root)}&limit=10` },
168
180
  { 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` },
181
+ { method: 'GET', path: '/api/kb/files/search', query: root => `projectRoot=${encodeURIComponent(root)}&q=${encodeURIComponent(marker)}&limit=50` },
170
182
  { method: 'GET', path: '/api/kb/duplicates', query: root => `projectRoot=${encodeURIComponent(root)}` },
171
183
  { method: 'GET', path: '/api/kb/operations', query: root => `projectRoot=${encodeURIComponent(root)}` },
172
184
  { method: 'GET', path: '/api/prompt' },
@@ -201,13 +213,13 @@ async function verifyWebSurface(baseUrl, root, label) {
201
213
  assert(res.status === 202 && res.json.success, `${sample.name} upload failed: ${res.status} ${res.raw}`);
202
214
  const relativePath = res.json.relativePath;
203
215
  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}`);
216
+ await waitFor(`${sample.name} background upload operation`, async () => {
217
+ const progress = await request('GET', `${base}/api/kb/operations?projectRoot=${encodeURIComponent(projectRoot)}`);
218
+ assert(progress.status === 200, `${sample.name} operations failed: ${progress.status}`);
219
+ const operation = progress.json.operations?.find(item => item.id === uploadId);
220
+ if (operation?.status === 'error') throw new Error(operation.error || operation.message);
221
+ return operation?.status === 'success' ? operation : undefined;
222
+ }, 120000);
211
223
  const detail = await waitFor(`${sample.name} indexed detail`, async () => {
212
224
  const current = await request('GET', `${base}/api/kb/files/detail?projectRoot=${encodeURIComponent(projectRoot)}&relativePath=${encodeURIComponent(relativePath)}`);
213
225
  if (current.status !== 200) throw new Error(`${sample.name} detail failed: ${current.status} ${current.raw}`);
@@ -216,16 +228,23 @@ async function verifyWebSurface(baseUrl, root, label) {
216
228
  }, 120000);
217
229
  if (!sample.allowZeroChunks && sample.searchable !== false) {
218
230
  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`);
231
+ const current = await request('GET', `${base}/api/kb/files/search?projectRoot=${encodeURIComponent(projectRoot)}&q=${encodeURIComponent(sample.query ?? marker)}&limit=500`);
220
232
  if (current.status !== 200) throw new Error(`${sample.name} search failed: ${current.status} ${current.raw}`);
221
- return searchHasHit(current, relativePath, marker) ? current : undefined;
233
+ return searchHasHit(current, relativePath) ? current : undefined;
222
234
  }, 120000);
223
- assert(searchHasHit(search, relativePath, marker), `${sample.name} search did not include marker hit`);
235
+ assert(searchHasHit(search, relativePath), `${sample.name} search did not include marker hit`);
224
236
  }
237
+ const preview = await request('GET', `${base}/api/kb/files/source-preview?projectRoot=${encodeURIComponent(projectRoot)}&relativePath=${encodeURIComponent(relativePath)}`);
238
+ assert(preview.status === 200 && preview.json.status === 'recorded' && preview.json.conservation?.status === 'verified'
239
+ && preview.json.conservation.chunkCountMatches && !preview.json.conservation.staleChunkIdentities.length, `${sample.name} parsed source/chunk conservation failed`);
240
+ if (!sample.allowZeroChunks) assert(preview.json.text?.includes(sample.expectedText ?? marker)
241
+ && (!sample.additionalText || preview.json.text.includes(sample.additionalText)), `${sample.name} indexed text lost submitted content`);
242
+ else assert(detail.json.file?.chunkCount === 0 && preview.json.text === '', `${sample.name} empty image produced fictional source text`);
225
243
  console.log('UPLOAD', sample.kind, sample.name, JSON.stringify({ relativePath, chunks: detail.json.file?.chunkCount, vector: res.json.vectorStatus?.status }));
226
244
  }
227
245
 
228
- const incrementalPath = path.join(projectRoot, 'knowledgeBase', '文档资料', 'incremental-local.txt');
246
+ const sdk = await import(require.resolve('@customize-agent/knowledge', { paths: [serverRoot] }));
247
+ const incrementalPath = path.join(sdk.getProjectKbPath(projectRoot, path.join(uploadDataHome, '.customize-agent')), '文档资料', 'incremental-local.txt');
229
248
  fs.mkdirSync(path.dirname(incrementalPath), { recursive: true });
230
249
  fs.writeFileSync(incrementalPath, text('incremental-local'));
231
250
  const reindexAll = await request('POST', `${base}/api/kb/reindex`, { projectRoot });