@sanqianx/project-knowledge 5.0.17 → 5.0.18-rc.2

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/package.json CHANGED
@@ -1,108 +1,108 @@
1
- {
2
- "name": "@sanqianx/project-knowledge",
3
- "version": "5.0.17",
4
- "description": "Knowledge base manager with Git integration, AI-driven analysis, and bilingual (zh-CN/en-US) knowledge output",
5
- "main": "_site/server.js",
6
- "scripts": {
7
- "start": "node _site/server.js",
8
- "test": "node _site/_test/run-all-tests.js",
9
- "release:sync": "node _site/scripts/sync-release-version.js --web-only",
10
- "vendor:modules": "node _site/scripts/vendor-modules.js",
11
- "runtime:verify": "node _site/scripts/verify-module-runtime.js --working-tree",
12
- "release:verify": "node _site/scripts/sync-release-version.js --check --web-only && node _site/scripts/verify-module-runtime.js && node _site/scripts/verify-product-runtime.js && node _site/_test/integration-adapters-test.js",
13
- "preversion": "npm run release:verify",
14
- "version": "node _site/scripts/sync-release-version.js --stage --web-only",
15
- "postversion": "npm run release:verify"
16
- },
17
- "bin": {
18
- "project-knowledge": "bin/project-knowledge.js",
19
- "project-knowledge-kb": "bin/project-knowledge-kb.js",
20
- "project-knowledge-mcp": "bin/project-knowledge-mcp.js",
21
- "project-knowledge-integrations": "bin/project-knowledge-integrations.js"
22
- },
23
- "engines": {
24
- "node": ">=22"
25
- },
26
- "files": [
27
- "_site/server.js",
28
- "ui/index.html",
29
- "ui/product.css",
30
- "ui/product.js",
31
- "ui/live-client.js",
32
- "ui/favicon.svg",
33
- "_site/lib/",
34
- "_modules/knowledge-engine/",
35
- "vendor-manifest.json",
36
- "module-runtime-manifest.json",
37
- "_site/scripts/",
38
- "_site/_test/*.js",
39
- "_site/_test/fixtures/",
40
- "_site/start.bat",
41
- "_site/stop.bat",
42
- "claude-prompts.json",
43
- "bin/",
44
- "plugins/",
45
- ".claude-plugin/",
46
- ".agents/plugins/",
47
- "templates/",
48
- "docs/assets/",
49
- "docs/README.zh-CN.md",
50
- "docs/project-registry-schema.md",
51
- "docs/team-knowledge-mode-a-plan.md",
52
- "docs/testing-strategy.md",
53
- "docs/leader-glm-workbench-playbook.md",
54
- "docs/release-5.0.16-acceptance.md",
55
- "docs/release-5.0.17-acceptance.md",
56
- "docs/fresh-v5-start.md",
57
- "README.md",
58
- "NOTICE",
59
- "CHANGELOG.md"
60
- ],
61
- "repository": {
62
- "type": "git",
63
- "url": "git+https://github.com/SanQianX/project-knowledge-base.git"
64
- },
65
- "keywords": [
66
- "knowledge-base",
67
- "git",
68
- "ai",
69
- "claude",
70
- "codex",
71
- "opencode",
72
- "mcp",
73
- "documentation",
74
- "scanner",
75
- "context-pack",
76
- "post-commit-hook"
77
- ],
78
- "author": "SanQianX",
79
- "license": "Apache-2.0",
80
- "dependencies": {
81
- "@anthropic-ai/claude-agent-sdk": "^0.2.141",
82
- "@grpc/grpc-js": "^1.14.5",
83
- "@grpc/proto-loader": "^0.8.1",
84
- "@huggingface/transformers": "3.8.1",
85
- "@lancedb/lancedb": "0.31.0",
86
- "@modelcontextprotocol/sdk": "1.29.0",
87
- "@sanqianx/ai-coding-event-bridge-console": "0.7.2",
88
- "@sanqianx/vector-hub": "1.0.8-rc.8",
89
- "buffer": "^6.0.3",
90
- "cheerio": "^1.2.0",
91
- "claude-ai-workbench": "npm:@sanqianx/claude-ai-workbench@0.13.2-rc.17",
92
- "cross-spawn": "7.0.6",
93
- "dotenv": "^17.4.2",
94
- "gpt-tokenizer": "^3.4.0",
95
- "http-proxy-agent": "7.0.2",
96
- "https-proxy-agent": "7.0.6",
97
- "json-colorizer": "^3.0.1",
98
- "jsonc-parser": "3.3.1",
99
- "openai": "^6.49.0",
100
- "socks-proxy-agent": "8.0.5",
101
- "turndown": "^7.2.4",
102
- "uuid": "^13.0.2",
103
- "wink-bm25-text-search": "^3.1.2",
104
- "wink-nlp": "^2.4.0",
105
- "ws": "^8.21.0",
106
- "yargs": "^18.1.0"
107
- }
108
- }
1
+ {
2
+ "name": "@sanqianx/project-knowledge",
3
+ "version": "5.0.18-rc.2",
4
+ "description": "Knowledge base manager with Git integration, AI-driven analysis, and bilingual (zh-CN/en-US) knowledge output",
5
+ "main": "_site/server.js",
6
+ "scripts": {
7
+ "start": "node _site/server.js",
8
+ "test": "node _site/_test/run-all-tests.js",
9
+ "release:sync": "node _site/scripts/sync-release-version.js --web-only",
10
+ "vendor:modules": "node _site/scripts/vendor-modules.js",
11
+ "runtime:verify": "node _site/scripts/verify-module-runtime.js --working-tree",
12
+ "release:verify": "node _site/scripts/sync-release-version.js --check --web-only && node _site/scripts/verify-module-runtime.js && node _site/scripts/verify-product-runtime.js && node _site/_test/integration-adapters-test.js",
13
+ "preversion": "npm run release:verify",
14
+ "version": "node _site/scripts/sync-release-version.js --stage --web-only",
15
+ "postversion": "npm run release:verify"
16
+ },
17
+ "bin": {
18
+ "project-knowledge": "bin/project-knowledge.js",
19
+ "project-knowledge-kb": "bin/project-knowledge-kb.js",
20
+ "project-knowledge-mcp": "bin/project-knowledge-mcp.js",
21
+ "project-knowledge-integrations": "bin/project-knowledge-integrations.js"
22
+ },
23
+ "engines": {
24
+ "node": ">=22"
25
+ },
26
+ "files": [
27
+ "_site/server.js",
28
+ "ui/index.html",
29
+ "ui/product.css",
30
+ "ui/product.js",
31
+ "ui/live-client.js",
32
+ "ui/favicon.svg",
33
+ "_site/lib/",
34
+ "_modules/knowledge-engine/",
35
+ "vendor-manifest.json",
36
+ "module-runtime-manifest.json",
37
+ "_site/scripts/",
38
+ "_site/_test/*.js",
39
+ "_site/_test/fixtures/",
40
+ "_site/start.bat",
41
+ "_site/stop.bat",
42
+ "claude-prompts.json",
43
+ "bin/",
44
+ "plugins/",
45
+ ".claude-plugin/",
46
+ ".agents/plugins/",
47
+ "templates/",
48
+ "docs/assets/",
49
+ "docs/README.zh-CN.md",
50
+ "docs/project-registry-schema.md",
51
+ "docs/team-knowledge-mode-a-plan.md",
52
+ "docs/testing-strategy.md",
53
+ "docs/leader-glm-workbench-playbook.md",
54
+ "docs/release-5.0.16-acceptance.md",
55
+ "docs/release-5.0.17-acceptance.md",
56
+ "docs/fresh-v5-start.md",
57
+ "README.md",
58
+ "NOTICE",
59
+ "CHANGELOG.md"
60
+ ],
61
+ "repository": {
62
+ "type": "git",
63
+ "url": "git+https://github.com/SanQianX/project-knowledge-base.git"
64
+ },
65
+ "keywords": [
66
+ "knowledge-base",
67
+ "git",
68
+ "ai",
69
+ "claude",
70
+ "codex",
71
+ "opencode",
72
+ "mcp",
73
+ "documentation",
74
+ "scanner",
75
+ "context-pack",
76
+ "post-commit-hook"
77
+ ],
78
+ "author": "SanQianX",
79
+ "license": "Apache-2.0",
80
+ "dependencies": {
81
+ "@anthropic-ai/claude-agent-sdk": "^0.2.141",
82
+ "@grpc/grpc-js": "^1.14.5",
83
+ "@grpc/proto-loader": "^0.8.1",
84
+ "@huggingface/transformers": "3.8.1",
85
+ "@lancedb/lancedb": "0.31.0",
86
+ "@modelcontextprotocol/sdk": "1.29.0",
87
+ "@sanqianx/ai-coding-event-bridge-console": "0.7.2",
88
+ "@sanqianx/vector-hub": "1.0.8-rc.8",
89
+ "buffer": "^6.0.3",
90
+ "cheerio": "^1.2.0",
91
+ "claude-ai-workbench": "npm:@sanqianx/claude-ai-workbench@0.13.2-rc.18",
92
+ "cross-spawn": "7.0.6",
93
+ "dotenv": "^17.4.2",
94
+ "gpt-tokenizer": "^3.4.0",
95
+ "http-proxy-agent": "7.0.2",
96
+ "https-proxy-agent": "7.0.6",
97
+ "json-colorizer": "^3.0.1",
98
+ "jsonc-parser": "3.3.1",
99
+ "openai": "^6.49.0",
100
+ "socks-proxy-agent": "8.0.5",
101
+ "turndown": "^7.2.4",
102
+ "uuid": "^13.0.2",
103
+ "wink-bm25-text-search": "^3.1.2",
104
+ "wink-nlp": "^2.4.0",
105
+ "ws": "^8.21.0",
106
+ "yargs": "^18.1.0"
107
+ }
108
+ }
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "project-knowledge",
4
4
  "hooks": "./hooks/claude.json",
5
- "version": "5.0.17",
5
+ "version": "5.0.18-rc.2",
6
6
  "description": "Read durable project decisions and implementation history from Project Knowledge.",
7
7
  "author": {
8
8
  "name": "SanQianX",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-knowledge",
3
- "version": "5.0.17",
3
+ "version": "5.0.18-rc.2",
4
4
  "description": "Read durable project decisions and implementation history from Project Knowledge.",
5
5
  "author": {
6
6
  "name": "SanQianX",
@@ -8,7 +8,7 @@
8
8
  "const fs=require('fs'),path=require('path'),os=require('os');const PKG='@sanqianx/project-knowledge',SC='project-knowledge/integration-runtime/v1';let f='';const root=process.env.CLAUDE_PLUGIN_ROOT||process.env.PLUGIN_ROOT;if(root){f=path.join(root,'scripts','mcp-launcher.cjs');if(!fs.existsSync(f))f=''}if(!f){const dd=process.env.KB_DATA_DIR||path.join(os.homedir(),'.project-knowledge-v5');try{const bp=path.join(dd,'integration-runtime.json');const st=fs.statSync(bp);if(st.isFile()&&st.size<=32768){const b=JSON.parse(fs.readFileSync(bp,'utf8'));if(b&&b.schema===SC&&b.packageName===PKG&&typeof b.packageRoot==='string'&&path.isAbsolute(b.packageRoot)){const c=path.join(b.packageRoot,'plugins','project-knowledge','scripts','mcp-launcher.cjs');const rr=fs.realpathSync(b.packageRoot),cr=fs.realpathSync(c);const rel=path.relative(rr,cr);if(rel&&rel!=='..'&&!rel.startsWith('..'+path.sep)&&!path.isAbsolute(rel)&&fs.statSync(cr).isFile())f=cr}}}catch(e){}}if(!f){console.error('[project-knowledge-mcp] 未能通过受信任插件根或已验证的安装绑定定位启动器,已停止;不访问网络,也不加载工作目录源码。');process.exit(127)}require(f);"
9
9
  ],
10
10
  "env": {
11
- "KB_PLUGIN_VERSION": "5.0.17"
11
+ "KB_PLUGIN_VERSION": "5.0.18-rc.2"
12
12
  }
13
13
  }
14
14
  }
package/ui/index.html CHANGED
@@ -37,7 +37,7 @@
37
37
  <header><h2>系统状态</h2><button id="closeSystem" class="icon-button" aria-label="关闭系统状态">×</button></header>
38
38
  <div class="drawer-content">
39
39
  <section><h3>模块连接</h3><div id="moduleHealth"></div><button id="repairWiring">修复当前项目接线</button><p class="muted" id="wiringFeedback"></p><p class="muted" id="captureStatus"></p></section>
40
- <section id="agentCaptureSection"><div class="actions"><h3>外部 Agent 接入</h3><button id="refreshAgentCapture">检查状态</button></div><p class="muted">知识读取与会话采集分别检查。只接入你使用的工具,不重装 Agent、不覆盖第三方配置。</p><div id="agentCaptureList"></div><p id="agentCaptureFeedback" class="feedback" role="status"></p></section>
40
+ <section id="agentCaptureSection"><div class="actions"><h3>外部 Agent 接入</h3></div><p class="muted">接入过的 Agent 配置损坏时会在启动时自动修复;只接入你使用的工具,不重装 Agent、不覆盖第三方配置。</p><div id="agentCaptureList"></div><p id="agentCaptureFeedback" class="feedback" role="status"></p></section>
41
41
  <section><h3>后台维护模型</h3><p class="muted">使用持久化默认模型,不跟随聊天中的临时切换。</p><select id="maintenanceModel" aria-label="后台维护默认模型"></select><div class="actions"><button id="saveMaintenance">保存默认模型</button><button id="configureProviders">管理模型供应商</button></div><p id="configurationStatus" class="muted"></p></section>
42
42
  <section><h3>向量检索模型</h3><p id="embeddingStatus" class="muted">正在读取配置。</p><button id="openEmbedding">配置向量模型</button><p class="muted">凭据由工作台统一保存。未配置时仍可使用文本检索。</p></section>
43
43
  <section><h3>智脑设置</h3><label>名称<input id="brainName" maxlength="100"></label><label>知识根目录<div class="input-with-action"><input id="knowledgeRoot"><button id="pickRoot">选择</button></div></label><label>向量索引目录<output id="indexStoragePath" class="detail-path"></output></label><p id="indexStorageStatus" class="muted"></p><p class="muted">索引跟随知识根目录,可重新构建;切换时原索引保留,已有项目知识与共享知识不移动。</p><button id="saveBrainSettings">保存设置</button></section>
package/ui/product.css CHANGED
@@ -2,6 +2,7 @@
2
2
  label>.detail-path{display:block;width:100%;margin:8px 0 0;color:var(--text)}
3
3
  .memory-toolbar{display:flex;justify-content:space-between;align-items:center;gap:24px}.memory-meta{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px}.memory-evidence{margin-top:24px;border-top:1px solid var(--line);padding-top:16px}.memory-evidence summary{cursor:pointer;color:var(--muted)}.memory-evidence p,.memory-evidence blockquote{white-space:pre-wrap;overflow-wrap:anywhere}.memory-evidence blockquote{margin:16px 0;border-left:2px solid var(--line);padding-left:16px;color:var(--muted)}
4
4
  .agent-capture-row{display:flex;align-items:center;gap:16px;padding:16px 0;border-bottom:1px solid var(--line)}.agent-capture-row>div:first-child{flex:1;min-width:0}.agent-capture-row small{display:block;color:var(--muted);margin-top:8px;overflow-wrap:anywhere}.agent-capture-row .actions{flex-shrink:0}#agentCaptureFeedback{white-space:pre-wrap}
5
+ .agent-detail{margin-top:8px}.agent-detail summary{cursor:pointer;color:var(--muted);font-size:12px;user-select:none}.agent-detail[open] summary{margin-bottom:2px}.agent-detail .actions{margin-top:8px}
5
6
  #logsDialog{display:flex;flex-direction:column;overflow:hidden}#logsDialog:not([open]){display:none}#logsContent{overflow:auto;min-height:0;flex:1;margin-top:16px}#logsContent .row{align-items:flex-start;cursor:pointer}#logsContent pre{flex:1;min-width:0;margin:0}#logsContent .log-entry{border-bottom:1px solid var(--line)}#logsContent .log-detail{padding:16px;background:var(--surface2);max-height:320px;overflow:auto}#logsContent [data-level=warn],#logsContent [data-level=error],#logsContent [data-level=fatal]{color:var(--bad)}#logsContent .row time,#logsContent .row pre{color:inherit}
6
7
  @media(prefers-reduced-motion:reduce){*,*::before,*::after{scroll-behavior:auto!important;animation:none!important;transition:none!important}}
7
8
  .knowledge-context{overflow-x:hidden}.reference{overflow-wrap:anywhere}.reference small{min-width:0;max-width:100%}
package/ui/product.js CHANGED
@@ -289,7 +289,10 @@
289
289
  $('systemDrawer').hidden = false; $('drawerBackdrop').hidden = false;
290
290
  $('brainName').value = state.brain.name; $('knowledgeRoot').value = state.root;
291
291
  renderStorageInfo();
292
- await Promise.all([loadMaintenance(), loadAgentCapture()]);
292
+ // Opening the drawer is the explicit refresh point (the manual status
293
+ // button is gone): force a fresh scan so externally changed client
294
+ // configs are reflected instead of serving the 30s cache.
295
+ await Promise.all([loadMaintenance(), loadAgentCapture(true)]);
293
296
  }
294
297
  function renderStorageInfo() {
295
298
  $('indexStoragePath').textContent = state.indexStorage?.actualPath || state.indexStorage?.path || '设置知识根目录后自动确定';
@@ -307,45 +310,58 @@
307
310
  const result = await api('/api/integrations/status?' + params);
308
311
  if (projectId !== state.projectId) return;
309
312
  if (epoch !== captureEpoch) return;
313
+ const badgeState = { connected: 'up', error: 'issue' };
314
+ const badgeText = { checking: '检测中', connected: '已接入', disconnected: '未接入', error: '异常', 'not-detected': '未检测到' };
310
315
  $('agentCaptureList').innerHTML = result.clients.map(agent => {
311
316
  const capture = agent.developmentCapture;
312
317
  const found = agent.available || agent.configFound;
313
318
  const software = agent.available ? '检测到命令' : agent.configFound ? '检测到配置' : capture.state === 'checking' ? '正在检测客户端' : '未检测到';
314
- const status = capture.state === 'checking' ? '检查中' : !capture.ok ? '检查或接线异常' : capture.installed ? '已配置采集' : '未接入';
315
319
  const auto = agent.automaticContext;
316
320
  const mcp = agent.mcpStartup;
317
- const mcpLine = mcp ? `<small>MCP ${mcp.state === 'ready' ? '已通过' : '未通过'}${mcp.code ? `(${esc(mcp.code)})` : ''}${mcp.detail ? ` · ${esc(mcp.detail)}` : ''}</small>` : '';
318
- return `<div class="agent-capture-row"><div><b>${esc(agent.label)}</b><small>${esc(software)} · ${esc(status)}</small><small>${esc(capture.detail)}</small>${auto ? `<small>开发前知识:${esc(auto.detail)}</small>` : ''}${mcpLine}</div><div class="actions">${auto?.supported ? `<button data-agent-knowledge="install" data-agent-client="${esc(agent.client)}" ${!found || captureBusy ? 'disabled' : ''}>${auto.configured ? '检查/修复知识接入' : '接入/修复知识读取'}</button>` : ''}<button data-agent-capture="install" data-agent-client="${esc(agent.client)}" ${!found || captureBusy ? 'disabled' : ''}>${capture.installed ? '修复采集' : '接入采集'}</button>${capture.installed ? `<button data-agent-capture="uninstall" data-agent-client="${esc(agent.client)}" ${captureBusy ? 'disabled' : ''}>移除采集</button>` : ''}</div></div>`;
321
+ const mcpLine = mcp ? `MCP ${mcp.state === 'ready' ? '已通过' : '未通过'}${mcp.code ? `(${esc(mcp.code)})` : ''}${mcp.detail ? ` · ${esc(mcp.detail)}` : ''}` : '';
322
+ const repairLine = agent.repair ? `启动自动修复:${agent.repair.state === 'repaired' ? '成功' : `失败${agent.repair.error ? ` · ${esc(agent.repair.error)}` : ''}`}` : '';
323
+ const summary = agent.summary || 'checking';
324
+ const switchOn = summary === 'connected';
325
+ const details = [
326
+ `<small>${esc(software)} · ${esc(capture.detail || '')}</small>`,
327
+ auto ? `<small>开发前知识:${esc(auto.detail)}</small>` : '',
328
+ mcpLine ? `<small>${mcpLine}</small>` : '',
329
+ repairLine ? `<small>${repairLine}</small>` : '',
330
+ summary === 'error' ? `<div class="actions"><button data-agent-retry="1" data-agent-client="${esc(agent.client)}" ${captureBusy ? 'disabled' : ''}>重试修复</button></div>` : '',
331
+ ].filter(Boolean).join('');
332
+ return `<div class="agent-capture-row"><div><b>${esc(agent.label)}</b> ${badge(badgeText[summary] || summary, badgeState[summary] || '')}<details class="agent-detail"><summary>详情</summary>${details}</details></div><div class="actions"><button data-agent-switch="${switchOn ? 'uninstall' : 'install'}" data-agent-client="${esc(agent.client)}" ${!found || captureBusy ? 'disabled' : ''}>${switchOn ? '移除' : '接入'}</button></div></div>`;
319
333
  }).join('');
320
- if (['checking', 'refreshing'].includes(result.scan?.state)) captureScanTimer = setTimeout(() => {
334
+ const pendingScan = ['checking', 'refreshing'].includes(result.scan?.state)
335
+ || (result.clients || []).some(client => client.developmentCapture?.state === 'checking' || client.knowledgeIntegration?.state === 'checking' || client.summary === 'checking');
336
+ if (pendingScan) captureScanTimer = setTimeout(() => {
321
337
  if (epoch === captureEpoch && !$('systemDrawer').hidden) loadAgentCapture().catch(error => toast(error.message));
322
338
  }, 1500);
323
339
  } catch (error) { if (epoch === captureEpoch) $('agentCaptureList').textContent = `无法检查采集状态:${error.message}`; }
324
340
  }
325
- async function repairAgentKnowledge(client) {
341
+ async function changeAgentAccess(client, operation) {
326
342
  if (captureBusy) return;
327
343
  captureBusy = true; captureEpoch++;
328
- $('agentCaptureFeedback').textContent = '正在检查并更新知识插件,保留第三方配置…';
344
+ all('[data-agent-switch]').forEach(button => { button.disabled = true; });
345
+ $('agentCaptureFeedback').textContent = operation === 'install' ? '正在接入,保留第三方配置…' : '正在移除,已有记录保留…';
329
346
  try {
330
- const result = await api('/api/integrations/install', { method: 'POST', body: { clients: [client], knowledgeOnly: true } });
331
- const capability = result.clients[0]?.knowledgeIntegration;
332
- $('agentCaptureFeedback').textContent = result.complete && capability?.ok ? '知识接线操作已完成。请重新打开客户端;如客户端要求信任 Hook,请按原生提示确认,再检查前置读取状态。' : `知识接线未完成:${capability?.detail || '请查看系统诊断。'}\n操作 ID:${result.operationId || '—'}`;
333
- $('agentCaptureFeedback').classList.toggle('issue', !result.complete);
334
- } catch (error) { $('agentCaptureFeedback').textContent = `知识接线操作失败:${error.message}`; $('agentCaptureFeedback').classList.add('issue'); }
335
- finally { captureBusy = false; await loadAgentCapture(true); }
336
- }
337
- async function changeAgentCapture(client, operation) {
347
+ const result = await api(`/api/integrations/${operation}`, { method: 'POST', body: { clients: [client] } });
348
+ const success = result.complete === true;
349
+ $('agentCaptureFeedback').textContent = success
350
+ ? operation === 'install' ? '已接入。重新打开客户端后生效,实际记录可在活动页面查看。' : '已移除,第三方配置与已有记录保留。'
351
+ : `操作未完成,展开详情查看原因;更多请查系统诊断记录(操作 ID:${result.operationId || '—'})。`;
352
+ $('agentCaptureFeedback').classList.toggle('issue', !success);
353
+ } catch (error) { $('agentCaptureFeedback').textContent = `操作失败:${error.message}`; $('agentCaptureFeedback').classList.add('issue'); }
354
+ finally { captureBusy = false; await loadAgentCapture(); post('eventBridge', { type: 'kb:refresh-agents' }); }
355
+ }
356
+ async function retryAgentRepair(client) {
338
357
  if (captureBusy) return;
339
358
  captureBusy = true; captureEpoch++;
340
- all('[data-agent-capture]').forEach(button => { button.disabled = true; });
341
- $('agentCaptureFeedback').textContent = operation === 'install' ? '正在配置采集 Hook…' : '正在移除托管采集,已有记录保留…';
359
+ $('agentCaptureFeedback').textContent = '正在重试修复…';
342
360
  try {
343
- const result = await api(`/api/integrations/${operation}`, { method: 'POST', body: { clients: [client], captureOnly: true } });
344
- const capture = operation === 'install' ? result.clients[0]?.developmentCapture : result.capture[0];
345
- const success = result.complete === true && capture?.ok;
346
- $('agentCaptureFeedback').textContent = success ? operation === 'install' ? '采集配置已保存。请重新打开外部 Agent 会话,实际记录可在活动页面查看。' : '已移除托管采集,第三方配置与已有记录保留。' : `接入操作未完成:${capture?.detail || result.bridge?.detail || '请检查系统诊断记录。'}\n操作 ID:${result.operationId || '—'}`;
347
- $('agentCaptureFeedback').classList.toggle('issue', !success);
348
- } catch (error) { $('agentCaptureFeedback').textContent = `操作失败:${error.message}`; $('agentCaptureFeedback').classList.add('issue'); }
361
+ const result = await api('/api/integrations/install', { method: 'POST', body: { clients: [client] } });
362
+ $('agentCaptureFeedback').textContent = result.complete === true ? '修复成功,重新打开客户端后生效。' : `修复未完成,详情见系统诊断记录(操作 ID:${result.operationId || '—'})。`;
363
+ $('agentCaptureFeedback').classList.toggle('issue', result.complete !== true);
364
+ } catch (error) { $('agentCaptureFeedback').textContent = `修复失败:${error.message}`; $('agentCaptureFeedback').classList.add('issue'); }
349
365
  finally { captureBusy = false; await loadAgentCapture(); post('eventBridge', { type: 'kb:refresh-agents' }); }
350
366
  }
351
367
  async function loadLogs() {
@@ -473,8 +489,8 @@
473
489
  if (button.dataset.action === 'refresh') await refreshRegistry(true);
474
490
  if (button.dataset.action === 'repair') await repair();
475
491
  if (button.dataset.action === 'system') await openSystem();
476
- if (button.dataset.agentCapture) await changeAgentCapture(button.dataset.agentClient, button.dataset.agentCapture);
477
- if (button.dataset.agentKnowledge) await repairAgentKnowledge(button.dataset.agentClient);
492
+ if (button.dataset.agentSwitch) await changeAgentAccess(button.dataset.agentClient, button.dataset.agentSwitch);
493
+ if (button.dataset.agentRetry) await retryAgentRepair(button.dataset.agentClient);
478
494
  if (button.dataset.action === 'unbind') { const p = activeProject(); if (p && !unbinding) { unbindProjectId = p.projectId; $('unbindProjectName').textContent = `解绑「${p.name}」?`; $('unbindFeedback').textContent = ''; $('unbindDialog').showModal(); } }
479
495
  if (button.dataset.retryRun) { await api(`/api/engine/runs/${encodeURIComponent(button.dataset.retryRun)}/retry`, { method: 'POST', body: {} }); await refreshSnapshot(); }
480
496
  if (button.dataset.runPage !== undefined) await loadActivityPage(button.dataset.runPage || null);
@@ -506,7 +522,6 @@
506
522
  on('themeToggle', 'click', () => { document.documentElement.dataset.theme = document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'; localStorage.setItem('kb.theme', document.documentElement.dataset.theme); Object.keys(frames).forEach(key => post(key, { type: 'kb:theme', theme: document.documentElement.dataset.theme })); });
507
523
  on('openSystem', 'click', openSystem); on('closeSystem', 'click', closeSystem); on('drawerBackdrop', 'click', closeSystem);
508
524
  on('repairWiring', 'click', repair);
509
- on('refreshAgentCapture', 'click', () => captureBusy ? undefined : loadAgentCapture(true));
510
525
  on('configureProviders', 'click', () => { closeSystem(); setView('work'); initializeFrame('terminal'); if (frames.terminal.ready) post('terminal', { type: 'kb:open-settings' }); else frames.terminal.openSettings = true; });
511
526
  on('saveMaintenance', 'click', async () => { await api('/api/terminal/maintenance-default', { method: 'PUT', body: { profileId: $('maintenanceModel').value || null } }); const result = await api('/api/modules/configure', { method: 'POST', body: {} }); $('configurationStatus').textContent = result.configuration.model ? '后台默认模型已保存并同步。' : '配置已保存,后台运行配置尚未同步,请检查模块连接。'; });
512
527
  on('openEmbedding', 'click', openEmbedding);