@customize-agent/knowledge 3.0.10 → 3.0.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.
@@ -494,7 +494,13 @@ export class IndexStateStore {
494
494
  );
495
495
  `);
496
496
  this.initFts();
497
- this.setMetadata('schema_version', '2');
497
+ try {
498
+ if (this.getMetadata('schema_version') !== '2')
499
+ this.setMetadata('schema_version', '2');
500
+ }
501
+ catch {
502
+ // 受限环境中已有索引库可能以只读方式挂载;运行时元数据不是必需项。
503
+ }
498
504
  }
499
505
  initFts() {
500
506
  try {
@@ -32,7 +32,7 @@ export class KnowledgeBaseManager {
32
32
  relationshipDetector = new RelationshipDetector();
33
33
  embeddingProvider;
34
34
  vectorStores;
35
- configManager = new ProjectConfigManager();
35
+ configManager;
36
36
  projectConfig;
37
37
  lastSkippedFiles = [];
38
38
  llmProvider;
@@ -47,6 +47,7 @@ export class KnowledgeBaseManager {
47
47
  this.llmProvider = options.llmProvider;
48
48
  this.onProgress = options.onProgress;
49
49
  const storageRoot = options.storageRoot ?? path.join(os.homedir(), USER_DATA_DIR);
50
+ this.configManager = new ProjectConfigManager(storageRoot);
50
51
  let dbPath;
51
52
  if (this.scope === 'global') {
52
53
  this.kbPath = options.kbPath ?? path.join(storageRoot, GLOBAL_KNOWLEDGE_DIR);
@@ -366,18 +367,26 @@ export class KnowledgeBaseManager {
366
367
  return this.incrementalIndex();
367
368
  }
368
369
  getUploadRelativePath(fileName, targetRelativePath) {
369
- return targetRelativePath ?? this.defaultUploadRelativePath(fileName);
370
+ return targetRelativePath ? this.normalizeRelativePath(targetRelativePath) : this.defaultUploadRelativePath(fileName);
370
371
  }
371
372
  async uploadFile(fileName, content, targetRelativePath, onProgress, options = {}) {
372
373
  return this.uploadFiles([{ fileName, content, targetRelativePath }], onProgress, options);
373
374
  }
374
375
  async uploadFiles(files, onProgress, options = {}) {
375
376
  this.initialize();
377
+ const uploadedPaths = [];
376
378
  for (const file of files) {
377
379
  const relativePath = this.getUploadRelativePath(file.fileName, file.targetRelativePath);
378
380
  const targetPath = this.resolveKbRelativePath(relativePath);
379
381
  fs.mkdirSync(path.dirname(targetPath), { recursive: true });
380
382
  fs.writeFileSync(targetPath, file.content);
383
+ uploadedPaths.push(relativePath);
384
+ }
385
+ for (const relativePath of uploadedPaths) {
386
+ const record = this.store.listRecords().find(item => item.relativePath === relativePath);
387
+ if (record)
388
+ await this.deleteVectorFile(record.collectionName, relativePath);
389
+ this.store.deleteRecord(relativePath);
381
390
  }
382
391
  return this.incrementalIndex({ onProgress, vectorMode: options.vectorMode });
383
392
  }
@@ -10,13 +10,14 @@ export class MultiProjectManager {
10
10
  storageRoot;
11
11
  llmProvider;
12
12
  registry;
13
- configManager = new ProjectConfigManager();
13
+ configManager;
14
14
  projects = new Map();
15
15
  globalKB;
16
16
  constructor(storageRoot = path.join(os.homedir(), USER_DATA_DIR), llmProvider) {
17
17
  this.storageRoot = storageRoot;
18
18
  this.llmProvider = llmProvider;
19
19
  this.registry = new ProjectRegistry(path.join(storageRoot, 'projects', 'registry.db'));
20
+ this.configManager = new ProjectConfigManager(storageRoot);
20
21
  }
21
22
  async getProject(projectRoot) {
22
23
  const resolvedRoot = path.resolve(projectRoot);
@@ -1,8 +1,10 @@
1
1
  import type { ProjectConfig } from '../types.js';
2
- export declare function getProjectConfigPath(projectRoot: string): string;
2
+ export declare function getProjectConfigPath(projectRoot: string, storageRoot?: string): string;
3
3
  export declare function getProjectKbPath(projectRoot: string): string;
4
4
  export declare function ensureProjectCustomizeFile(projectRoot: string): void;
5
5
  export declare class ProjectConfigManager {
6
+ private readonly storageRoot;
7
+ constructor(storageRoot?: string);
6
8
  loadOrCreate(projectRoot: string): ProjectConfig;
7
9
  save(projectRoot: string, config: ProjectConfig): void;
8
10
  private withDefaults;
@@ -1,11 +1,11 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
  import * as os from 'node:os';
4
- import { DEFAULT_CATEGORY_DIRS, KNOWLEDGE_BASE_DIR, PROJECT_CONFIG_PATH, USER_DATA_DIR } from '../constants.js';
4
+ import { DEFAULT_CATEGORY_DIRS, KNOWLEDGE_BASE_DIR, USER_DATA_DIR } from '../constants.js';
5
5
  import { computeProjectId } from './project-id.js';
6
- export function getProjectConfigPath(projectRoot) {
6
+ export function getProjectConfigPath(projectRoot, storageRoot = path.join(os.homedir(), USER_DATA_DIR)) {
7
7
  const projectId = computeProjectId(projectRoot);
8
- return path.join(os.homedir(), USER_DATA_DIR, 'projects', projectId, ...PROJECT_CONFIG_PATH.slice(1));
8
+ return path.join(storageRoot, 'projects', projectId, 'project.json');
9
9
  }
10
10
  export function getProjectKbPath(projectRoot) {
11
11
  return path.join(projectRoot, KNOWLEDGE_BASE_DIR);
@@ -35,22 +35,24 @@ export function ensureProjectCustomizeFile(projectRoot) {
35
35
  }
36
36
  }
37
37
  export class ProjectConfigManager {
38
+ storageRoot;
39
+ constructor(storageRoot = path.join(os.homedir(), USER_DATA_DIR)) {
40
+ this.storageRoot = storageRoot;
41
+ }
38
42
  loadOrCreate(projectRoot) {
39
43
  ensureProjectCustomizeFile(projectRoot);
40
- const configPath = getProjectConfigPath(projectRoot);
44
+ const configPath = getProjectConfigPath(projectRoot, this.storageRoot);
41
45
  const now = Date.now();
42
46
  if (fs.existsSync(configPath)) {
43
47
  const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'));
44
- const config = this.withDefaults(projectRoot, raw, now);
45
- this.save(projectRoot, { ...config, lastOpenedAt: now });
46
- return { ...config, lastOpenedAt: now };
48
+ return this.withDefaults(projectRoot, raw, now);
47
49
  }
48
50
  const config = this.withDefaults(projectRoot, {}, now);
49
51
  this.save(projectRoot, config);
50
52
  return config;
51
53
  }
52
54
  save(projectRoot, config) {
53
- const configPath = getProjectConfigPath(projectRoot);
55
+ const configPath = getProjectConfigPath(projectRoot, this.storageRoot);
54
56
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
55
57
  fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
56
58
  }
@@ -17,6 +17,7 @@ export declare class ContentExtractor {
17
17
  private textScore;
18
18
  private extractCad;
19
19
  private extractDxf;
20
+ private tryConvertDwgWithBundledWasm;
20
21
  private tryConvertDwgToDxf;
21
22
  private extractCadMesh;
22
23
  private getTempRoot;
@@ -333,10 +333,30 @@ export class ContentExtractor {
333
333
  warnings,
334
334
  };
335
335
  }
336
+ async tryConvertDwgWithBundledWasm(filePath) {
337
+ try {
338
+ const mod = await resolveAndImport('dwgdxf');
339
+ if (!mod.convertDwgToDxf)
340
+ return { tool: 'dwgdxf_wasm', warnings: ['内置 dwgdxf WASM 转换器未导出 convertDwgToDxf'] };
341
+ const dxfBytes = await mod.convertDwgToDxf(fs.readFileSync(filePath));
342
+ const dxfText = Buffer.from(dxfBytes).toString('utf8');
343
+ return dxfText.trim()
344
+ ? { dxfText, tool: 'dwgdxf_wasm', warnings: [] }
345
+ : { tool: 'dwgdxf_wasm', warnings: ['内置 dwgdxf WASM 转换器未输出 DXF 文本'] };
346
+ }
347
+ catch (error) {
348
+ return { tool: 'dwgdxf_wasm', warnings: [`内置 dwgdxf WASM 转换失败: ${error instanceof Error ? error.message : String(error)}`] };
349
+ }
350
+ }
336
351
  async tryConvertDwgToDxf(filePath) {
337
352
  const tmpDir = fs.mkdtempSync(path.join(this.getTempRoot(), 'customize-dwg-'));
338
353
  const outputPath = path.join(tmpDir, `${path.basename(filePath, path.extname(filePath))}.dxf`);
339
354
  try {
355
+ const failures = [];
356
+ const bundled = await this.tryConvertDwgWithBundledWasm(filePath);
357
+ if (bundled.dxfText)
358
+ return bundled;
359
+ failures.push(...bundled.warnings);
340
360
  const customCmd = process.env.CUSTOMIZE_DWG_TO_DXF_CMD;
341
361
  if (customCmd) {
342
362
  if (/\s/u.test(customCmd))
@@ -357,7 +377,6 @@ export class ContentExtractor {
357
377
  return { dxfText: fs.readFileSync(outputPath, 'utf8'), tool: 'external_dwg_to_dxf', warnings: [] };
358
378
  return { tool: 'external_dwg_to_dxf', warnings: [`CUSTOMIZE_DWG_TO_DXF_CMD 转换失败: ${result.stderr || result.stdout || result.error?.message || 'unknown error'}`] };
359
379
  }
360
- const failures = [];
361
380
  for (const bin of ['dwgread', 'dwg2dxf']) {
362
381
  const result = spawnSync(bin, bin === 'dwgread' ? ['-O', 'DXF', '-o', outputPath, filePath] : [filePath, outputPath], { encoding: 'utf8', timeout: 120_000 });
363
382
  if (result.status === 0 && fs.existsSync(outputPath))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@customize-agent/knowledge",
3
- "version": "3.0.10",
3
+ "version": "3.0.11",
4
4
  "description": "Local knowledge base infrastructure for customize-agent",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -37,6 +37,7 @@
37
37
  "dependencies": {
38
38
  "@napi-rs/canvas": "^0.1.82",
39
39
  "better-sqlite3": "^12.10.0",
40
+ "dwgdxf": "^2.0.1",
40
41
  "dxf-parser": "^1.1.2",
41
42
  "fast-glob": "^3.3.3",
42
43
  "jszip": "^3.10.1",