@sanqianx/project-knowledge 5.0.9-rc.12 → 5.0.9-rc.14

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.
@@ -9,7 +9,7 @@
9
9
  "plugins": [
10
10
  {
11
11
  "name": "project-knowledge",
12
- "version": "5.0.9-rc.12",
12
+ "version": "5.0.9-rc.14",
13
13
  "source": "./plugins/project-knowledge",
14
14
  "description": "Search durable project decisions and implementation history through MCP."
15
15
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.0.9-rc.14] - 2026-10-11
4
+
5
+ - Vendor engine 0.2.3-rc.7: isolated maintenance consumes frozen evidence even
6
+ while the user edits or commits in the source repository. Do not mistake live
7
+ development for analyzer writes; retain live-source protection for custom
8
+ analyzers without the isolation capability.
9
+ - Add a paused child-worker regression covering another commit, uncommitted
10
+ drafts, frozen attribution, same-project FIFO and unchanged path/tool guards.
11
+ - Existing-user npm acceptance verified real MiniMax streaming, retained v5
12
+ history/configuration, D-root indexes and index-only e9f6560 recovery. Preserve
13
+ the actual rc.13 PROJECT_BUSY failure and require a real mid-analysis commit
14
+ retest from downloaded rc.14 before stable promotion.
15
+
16
+ ## [5.0.9-rc.13] - 2026-10-11
17
+
18
+ - Give native Agent session creation and input setup a bounded 90-second proxy
19
+ budget. Ordinary API reads/abort/permissions retain 10 seconds; SSE streaming
20
+ and folder-picker contracts are unchanged.
21
+ - Record safe proxy failure categories and deadlines without raw errors or URL
22
+ queries. Preserve MODULE_UNREACHABLE compatibility and add optional details.
23
+ - Reproduce the installed OpenCode cold-start failure with a real delayed HTTP
24
+ server; verify the targeted budget, unrelated routes and credential redaction.
25
+ - Retain rc.12 real acceptance and failed OpenCode results separately; require
26
+ a newly downloaded candidate and cold-client retest before user upgrade.
27
+
3
28
  ## [5.0.9-rc.12] - 2026-10-11
4
29
 
5
30
  - Vendor engine 0.2.3-rc.6 to address the Windows transient state-file rename
@@ -41,6 +41,8 @@ node src/bin.js serve [--port 5790] [--host 127.0.0.1] [--data DIR]
41
41
 
42
42
  本模块零新增 npm 依赖、CommonJS、Node ≥18;无头 Agent SDK 由宿主已安装的 Workbench/SDK 提供,缺失时明确失败,不退回假分析。完整产品的 Node 门槛为 ≥22。
43
43
 
44
+ 隔离无头分析只读冻结证据、只写 staging,不以开发工作树的前后变化判定失败。用户可以在分析中继续编辑或提交;当前任务仍归属冻结提交,后续提交按项目 FIFO 执行。未声明隔离冻结证据能力的自定义分析器仍保留源码变更检查;目录越界、工具权限和晋升校验不变。
45
+
44
46
  每次真实分析在只读证据区冻结已有知识的目标路径与哈希清单,覆盖未被检索选中的文件;重试复用该清单。Agent 不得把“未检索到”当作“文件不存在”,也不得用部分片段覆盖完整旧文档;无法保留原文时只追加当前提交的变更记录。已有目标仍由晋升校验拒绝非法 create,不自动改为覆盖。清单仅保存元数据,不把整个知识树复制到每次运行中。
45
47
 
46
48
  ## API
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanqianx/ai-coding-knowledge-engine",
3
- "version": "0.2.3-rc.6",
3
+ "version": "0.2.3-rc.7",
4
4
  "description": "Knowledge engine module for project-knowledge: commit-boundary triggered knowledge analysis/generation (trigger plane) and retrieval for development assistants (retrieval plane).",
5
5
  "license": "Apache-2.0",
6
6
  "main": "src/server.js",
@@ -50,7 +50,7 @@ class EngineCoordinator extends EventEmitter {
50
50
  this.retrieval = new EngineRetrieval({ layout: this.layout, projectStore: this.projectStore, registryStore, store, memories: this.memories, vectorUrl: this.vectorUrl });
51
51
  this.conversations = new ConversationStore({ layout: this.layout, projectStore: this.projectStore });
52
52
  this.analyzer = options.analyzer || new HeadlessAnalyzer({ resolveProfile: id => this.profiles.get(id) || this.profiles.get('default'), timeoutMs: options.timeoutMs });
53
- this.promotion = new KnowledgePromotionService({ layout: this.layout, logger: this.diagnostics, projectStore: this.projectStore, analyzer: { runClaim: async input => {
53
+ this.promotion = new KnowledgePromotionService({ layout: this.layout, logger: this.diagnostics, projectStore: this.projectStore, analyzer: { sourceReadMode: this.analyzer.sourceReadMode, runClaim: async input => {
54
54
  const run = this.currentRun(input.projectId);
55
55
  store.updateRun(run.runId, { analysisRunId: input.claim.runId, phase: 'analyzing' });
56
56
  this.notify(run, '正在分析冻结的提交证据');
@@ -6,6 +6,7 @@ const { finalizeAnalysisOutput } = require('./analysis-output');
6
6
  const { freezeKnowledgeTargets } = require('./knowledge-targets');
7
7
 
8
8
  class HeadlessAnalyzer {
9
+ get sourceReadMode() { return 'isolated-frozen-evidence'; }
9
10
  constructor({ resolveProfile, timeoutMs = 15 * 60 * 1000, workerPath = path.join(__dirname, 'analysis-worker.js') } = {}) { this.resolveProfile = resolveProfile; this.timeoutMs = timeoutMs; this.workerPath = workerPath; this.children = new Map(); this.closed = false; }
10
11
  async runClaim(input) {
11
12
  if (this.closed) throw Object.assign(new Error('分析服务正在关闭。'), { code: 'WORKER_STOPPED', retryable: true });
@@ -312,7 +312,11 @@ class KnowledgePromotionService {
312
312
  if (!claim || claim.projectId !== projectId || !claim.runId || !claim.commitSha) throw new DomainError('INVALID_ARGUMENT', 'Active claim is required for knowledge promotion.');
313
313
  const operationId = input.operationId || claim.operationId || createId('op');
314
314
  const stagingPath = this.prepareStaging(projectId, claim.runId);
315
- const beforeSource = await gitStatus(config.repoPath);
315
+ // The isolated worker cannot read or write the live repository. A user may
316
+ // keep developing while it consumes frozen evidence; live status is neither
317
+ // its input nor proof of worker writes. Keep the guard for other analyzers.
318
+ const verifyLiveSource = this.analyzer?.sourceReadMode !== 'isolated-frozen-evidence';
319
+ const beforeSource = verifyLiveSource ? await gitStatus(config.repoPath) : null;
316
320
  try {
317
321
  if (!this.analyzer || typeof this.analyzer.runClaim !== 'function') throw new DomainError('INVALID_ARGUMENT', 'Knowledge analyzer is unavailable.', { status: 503, retryable: true });
318
322
  const analyzerResult = await this.analyzer.runClaim({
@@ -329,7 +333,7 @@ class KnowledgePromotionService {
329
333
  }),
330
334
  });
331
335
  if (analyzerResult && analyzerResult.ok === false) throw new DomainError('INVALID_ARGUMENT', analyzerResult.error || 'Knowledge analyzer failed.', { status: 500, retryable: true });
332
- const afterSource = await gitStatus(config.repoPath);
336
+ const afterSource = verifyLiveSource ? await gitStatus(config.repoPath) : null;
333
337
  if (beforeSource != null && afterSource != null && beforeSource !== afterSource) {
334
338
  throw new DomainError('PROJECT_BUSY', 'Source repository changed during knowledge analysis.', { status: 409, retryable: true });
335
339
  }
@@ -0,0 +1,65 @@
1
+ 'use strict';
2
+ const assert = require('node:assert/strict');
3
+ const http = require('node:http');
4
+ const { Readable } = require('node:stream');
5
+ const { EventEmitter } = require('node:events');
6
+ const { ModuleBridge } = require('../lib/module-bridge');
7
+
8
+ async function budget(method, pathname) {
9
+ const timers = [], originalTimer = global.setTimeout, originalFetch = global.fetch;
10
+ const req = Readable.from([]); req.method = method; req.headers = {};
11
+ const res = new EventEmitter();
12
+ res.writeHead = () => {}; res.end = () => { res.writableEnded = true; };
13
+ try {
14
+ global.setTimeout = (fn, ms, ...args) => { timers.push(ms); return originalTimer(fn, ms, ...args); };
15
+ global.fetch = async () => new Response('{}', { headers: { 'Content-Type': 'application/json' } });
16
+ await new ModuleBridge().proxy(req, res, 'http://127.0.0.1:5760' + pathname);
17
+ return timers[0];
18
+ } finally { global.setTimeout = originalTimer; global.fetch = originalFetch; }
19
+ }
20
+
21
+ (async () => {
22
+ const upstream = http.createServer((req, res) => {
23
+ const timer = setTimeout(() => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end('{"accepted":true}'); }, 11000);
24
+ res.on('close', () => clearTimeout(timer));
25
+ });
26
+ await new Promise(resolve => upstream.listen(0, '127.0.0.1', resolve));
27
+ const bridge = new ModuleBridge();
28
+ const target = `http://127.0.0.1:${upstream.address().port}/api/claude-workbench/v1/sessions/cold-client/input`;
29
+ const shell = http.createServer((req, res) => bridge.proxy(req, res, target));
30
+ await new Promise(resolve => shell.listen(0, '127.0.0.1', resolve));
31
+ try {
32
+ const response = await fetch(`http://127.0.0.1:${shell.address().port}/send`, { method: 'POST', body: '{}' });
33
+ assert.equal(response.status, 200, 'cold native client startup must not be reported as unreachable after ten seconds');
34
+ assert.equal((await response.json()).accepted, true);
35
+ } finally {
36
+ for (const server of [shell, upstream]) { server.closeAllConnections(); await new Promise(resolve => server.close(resolve)); }
37
+ }
38
+ assert.equal(await budget('POST', '/api/claude-workbench/v1/sessions'), 90000);
39
+ assert.equal(await budget('POST', '/api/claude-workbench/v1/sessions/cold-client/input?scope=project'), 90000);
40
+ for (const [method, route] of [
41
+ ['GET', '/api/claude-workbench/v1/sessions'],
42
+ ['POST', '/api/claude-workbench/v1/sessions/cold-client/abort'],
43
+ ['POST', '/api/claude-workbench/v1/sessions/cold-client/permission'],
44
+ ['POST', '/api/engine/runs'],
45
+ ['POST', '/api/sessions/cold-client/input'],
46
+ ]) assert.equal(await budget(method, route), 10000, 'unrelated APIs must keep their ordinary timeout');
47
+ assert.equal(await budget('POST', '/api/claude-workbench/v1/system/pick-folder'), 600000);
48
+ const originalFetch = global.fetch;
49
+ let warning, failure;
50
+ const request = Readable.from([]); request.method = 'GET'; request.headers = {};
51
+ const response = new EventEmitter(); response.writeHead = () => {};
52
+ response.end = bytes => { response.writableEnded = true; failure = JSON.parse(bytes); };
53
+ try {
54
+ global.fetch = async () => { throw new Error('upstream leaked credential: secret-proxy-fixture'); };
55
+ const safeBridge = new ModuleBridge({ logger: { warn(...args) { warning = args; } } });
56
+ await safeBridge.proxy(request, response, 'http://127.0.0.1:5760/api/health?apiKey=secret-proxy-fixture');
57
+ assert.equal(failure.error, 'MODULE_UNREACHABLE');
58
+ assert.equal(failure.details.failureKind, 'NETWORK_ERROR');
59
+ assert.equal(failure.details.timeoutMs, 10000);
60
+ assert.equal(warning[0], 'module.proxy.failed');
61
+ assert.equal(warning[2].context.path, '/api/health');
62
+ assert.ok(!JSON.stringify([failure, warning]).includes('secret-proxy-fixture'), 'diagnostics omit queries, raw errors and credentials');
63
+ } finally { global.fetch = originalFetch; }
64
+ console.log('module-agent-start-proxy-test PASS');
65
+ })().catch(error => { console.error(error); process.exitCode = 1; });
@@ -31,6 +31,9 @@ const { once } = require('events');
31
31
  const { DomainError } = require('./contracts');
32
32
 
33
33
  const PROXY_TIMEOUT_MS = 10000;
34
+ // Native client startup includes knowledge retrieval and a local server/CLI
35
+ // handshake. It has a bounded setup budget, separate from ordinary reads/SSE.
36
+ const AGENT_START_TIMEOUT_MS = 90000;
34
37
  // Registration drives a full embedding pass in vector-hub (remote API); a
35
38
  // fresh knowledge folder can easily exceed the interactive proxy budget.
36
39
  const REGISTER_TIMEOUT_MS = 60000;
@@ -131,7 +134,11 @@ class ModuleBridge {
131
134
  // The native folder pickers hold the request open until the user closes
132
135
  // the dialog — they need a human-scale budget, not the API budget.
133
136
  const isPicker = /\/(system\/)?pick-folder/.test(target);
134
- const timeoutMs = isPicker ? PICKER_TIMEOUT_MS : PROXY_TIMEOUT_MS;
137
+ const targetUrl = new URL(target);
138
+ const pathname = targetUrl.pathname;
139
+ const isAgentStart = req.method === 'POST' && /^\/api\/claude-workbench\/v1\/sessions(?:\/[^/]+\/input)?\/?$/.test(pathname);
140
+ const timeoutMs = isPicker ? PICKER_TIMEOUT_MS : isAgentStart ? AGENT_START_TIMEOUT_MS : PROXY_TIMEOUT_MS;
141
+ const startedAt = Date.now();
135
142
  let upstream;
136
143
  const controller = new AbortController();
137
144
  const timer = setTimeout(() => controller.abort(), timeoutMs);
@@ -148,8 +155,13 @@ class ModuleBridge {
148
155
  clearTimeout(timer);
149
156
  res.off?.('close', disconnected);
150
157
  if (res.destroyed) return;
158
+ const details = { failureKind: controller.signal.aborted ? 'UPSTREAM_TIMEOUT' : 'NETWORK_ERROR', timeoutMs };
159
+ this.logger.warn('module.proxy.failed', '模块请求未完成,请检查连接或客户端启动。', {
160
+ component: 'module-bridge', phase: 'proxy', durationMs: Date.now() - startedAt,
161
+ context: { ...details, method: req.method, path: pathname },
162
+ });
151
163
  res.writeHead(502, { 'Content-Type': 'application/json; charset=utf-8' });
152
- res.end(JSON.stringify({ ok: false, error: 'MODULE_UNREACHABLE', target }));
164
+ res.end(JSON.stringify({ ok: false, error: 'MODULE_UNREACHABLE', target: targetUrl.origin + pathname, details }));
153
165
  return;
154
166
  }
155
167
  const contentType = upstream.headers.get('content-type') || 'application/json; charset=utf-8';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanqianx/project-knowledge",
3
- "version": "5.0.9-rc.12",
3
+ "version": "5.0.9-rc.14",
4
4
  "description": "Knowledge base manager with Git integration, AI-driven analysis, and bilingual (zh-CN/en-US) knowledge output",
5
5
  "main": "_site/server.js",
6
6
  "scripts": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "project-knowledge",
4
- "version": "5.0.9-rc.12",
4
+ "version": "5.0.9-rc.14",
5
5
  "description": "Read durable project decisions and implementation history from Project Knowledge.",
6
6
  "author": {
7
7
  "name": "SanQianX",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-knowledge",
3
- "version": "5.0.9-rc.12",
3
+ "version": "5.0.9-rc.14",
4
4
  "description": "Read durable project decisions and implementation history from Project Knowledge.",
5
5
  "author": {
6
6
  "name": "SanQianX",
@@ -6,7 +6,7 @@
6
6
  "args": [
7
7
  "-y",
8
8
  "--package",
9
- "@sanqianx/project-knowledge@5.0.9-rc.12",
9
+ "@sanqianx/project-knowledge@5.0.9-rc.14",
10
10
  "project-knowledge-mcp"
11
11
  ]
12
12
  }
@@ -3,19 +3,19 @@
3
3
  "modules": {
4
4
  "knowledge-engine": {
5
5
  "name": "@sanqianx/ai-coding-knowledge-engine",
6
- "version": "0.2.3-rc.6",
6
+ "version": "0.2.3-rc.7",
7
7
  "root": "_modules/knowledge-engine",
8
8
  "files": {
9
- "README.md": "efcef635df01736a8672219642a76175f3059d23b466f529140d791ec75000d5",
10
- "package.json": "09e32aacd4ec5c3b596e60f3210f62515c625844e31866261c5596937195db30",
9
+ "README.md": "351d971a522253c5dceb424b9f1a9c2d9427cd01c2b76d0c37fbc17b76f71ba3",
10
+ "package.json": "2da4b42d29e6742ea4ac8f285ffc49da66e0ed44d1d0d136cfab1e1b485093b4",
11
11
  "src/analysis-contract.js": "fee063967d32eefc955cf0729f7dc8cb31bd690b85e22471c9059494a599c77a",
12
12
  "src/analysis-output.js": "95a3c19dcc9ab85d1dba7fee5b9aec80f9c000dfba89da3fd0be25a81e2fb680",
13
13
  "src/analysis-worker.js": "a105cabe6e1573b2d986b1e7a5aaf615e2fb53524156fc8e4e2c0a71f2c97e55",
14
14
  "src/bin.js": "22208907431d0f3a971a669c7e5eb44b3b7af9bbb36fd7ba17c3b90c4288bd70",
15
15
  "src/bridge-client.js": "ae0dba21e4286694bcd9e064ca36564ec997969ae1eb1ce4f8a6665e447cbffe",
16
- "src/coordinator.js": "1df096060faa83245c49b65a861f32cdaeeb7a190b94abf2ad6477151d7ca2ff",
16
+ "src/coordinator.js": "1d515d891a781fbad3ce7df39fa083dda2663a8bcd5610ff52dc8c307e2c5fbd",
17
17
  "src/diagnostics.js": "f7b516ace61a1e9faaa6876930b9e2e258499a25857d1203f4e53d28bfd0fa1a",
18
- "src/headless-analyzer.js": "2f345adee332c003ecb9a1e01eac4fa69d8802b4e6dd9effb03ac3cb19aa3e48",
18
+ "src/headless-analyzer.js": "d181d50cd7756d217d7d66c4a4c4e528453c8527dc6fe413a19788a47ccbf323",
19
19
  "src/index-request.js": "78f26b872299005499fff4f2d1f9e8f986784f2ff36a5cf2be2b1e7b7c7d9378",
20
20
  "src/knowledge-targets.js": "aa44ec285d16d7b1c0b63bf084058a1d6f867fa9929c753b6b0cbb24f7b20ee2",
21
21
  "src/memories.js": "0a8667e6daba99fa5022393951a28e96cdadf98af85b6af9a6be96c7f4e896fc",
@@ -33,7 +33,7 @@
33
33
  "src/runtime/conversation-store.js": "644318f9c04376a3317ced240dd94afa99a79631f0ecc394c5aa298ae2bc0474",
34
34
  "src/runtime/evidence-bundle.js": "33d4614849d5e1d69aba8b75c3a43c18b7b6f94e5c78654c82ef631331cc94cc",
35
35
  "src/runtime/git-runner.js": "b74fe197bd4dcf3e70635ef7b1f2615edf965c1d9a3ffe5406aabd41b76d74a9",
36
- "src/runtime/knowledge-promotion.js": "c24aba505caf11cdc8faba763beffc65956c1330ef28ed5fbd6ae16eac640fa6",
36
+ "src/runtime/knowledge-promotion.js": "892a227921ca399e80ea7b3991bfd13de0ffc221c7a0562393f1e5d33c2d00fa",
37
37
  "src/runtime/knowledge-retrieval-service.js": "75444f495a9ad0720af0e57b8d27d7ac1325c78a768f4f68ebd86ebc2524945e",
38
38
  "src/runtime/layout.js": "c48fa1db62e5df1edefe13218e470c5ceea4ef2781293512c2c18e5c2ba0c7e9",
39
39
  "src/runtime/markdown-knowledge-indexer.js": "4d6b5b955849d274ca0614ef030c94526da7c39ab0874f02c168d0681f5b1406",