@sanqianx/project-knowledge 5.0.19 → 5.0.20
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/.agents/plugins/marketplace.json +3 -3
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +5 -0
- package/LICENSE +201 -201
- package/NOTICE +5 -5
- package/README.md +349 -349
- package/_modules/knowledge-engine/README.md +4 -0
- package/_modules/knowledge-engine/src/analysis-failures.js +39 -0
- package/_modules/knowledge-engine/src/analysis-worker.js +6 -2
- package/_modules/knowledge-engine/src/coordinator.js +7 -0
- package/_modules/knowledge-engine/src/headless-analyzer.js +2 -1
- package/_modules/knowledge-engine/src/server.js +1 -1
- package/_site/_test/agent-capture-mcp-ui-test.js +67 -67
- package/_site/_test/ai-profile-test.js +75 -75
- package/_site/_test/ai-vendor-presets-test.js +91 -91
- package/_site/_test/automatic-context-test.js +70 -70
- package/_site/_test/bin-cli-test.js +230 -230
- package/_site/_test/bridge-adapter-test.js +95 -95
- package/_site/_test/bridge-consumer-service-test.js +310 -310
- package/_site/_test/candidate-bin-content-test.js +35 -35
- package/_site/_test/candidate-product-assets-test.js +13 -13
- package/_site/_test/candidate-release-contract-test.js +14 -14
- package/_site/_test/capture-hook-dedup-test.js +158 -158
- package/_site/_test/claude-executable-discovery-test.js +28 -28
- package/_site/_test/claude-session-lifecycle-sweep-test.js +252 -252
- package/_site/_test/cli-instance-management-test.js +62 -62
- package/_site/_test/client-capture-restart-e2e-test.js +189 -189
- package/_site/_test/codex-conversation-projection-test.js +60 -60
- package/_site/_test/codex-marketplace-scoped-path-test.js +186 -186
- package/_site/_test/codex-notify-capture-e2e-test.js +101 -101
- package/_site/_test/codex-notify-fanout-test.js +134 -134
- package/_site/_test/codex-notify-upgrade-test.js +253 -253
- package/_site/_test/commit-boundary-freeze-test.js +147 -147
- package/_site/_test/commit-conversation-binding-test.js +4 -4
- package/_site/_test/configuration-generation-test.js +22 -22
- package/_site/_test/context-pack-test.js +200 -200
- package/_site/_test/conversation-api-test.js +10 -10
- package/_site/_test/conversation-origin-test.js +15 -15
- package/_site/_test/cross-repo-isolation-e2e-test.js +187 -187
- package/_site/_test/embedding-config-test.js +32 -32
- package/_site/_test/fixtures/fake-browser-exit.js +10 -10
- package/_site/_test/fixtures/fake-browser-hang.js +10 -10
- package/_site/_test/fixtures/integration-busy-worker.cjs +6 -6
- package/_site/_test/fixtures/make-git-repos.js +92 -92
- package/_site/_test/fixtures/retrieval-gold-queries.json +32 -32
- package/_site/_test/fresh-hook-reimport-test.js +53 -53
- package/_site/_test/fresh-product-data-test.js +56 -56
- package/_site/_test/git-path-compatibility-test.js +80 -80
- package/_site/_test/git-validation-test.js +81 -81
- package/_site/_test/hook-worktree-test.js +42 -42
- package/_site/_test/index-builder-test.js +41 -41
- package/_site/_test/index-error-display-contract-test.js +10 -10
- package/_site/_test/integration-adapters-test.js +67 -67
- package/_site/_test/integration-capture-setup-test.js +118 -118
- package/_site/_test/integration-runtime-binding-a2-test.js +566 -566
- package/_site/_test/integration-runtime-binding-a3-test.js +227 -227
- package/_site/_test/integration-runtime-binding-test.js +473 -473
- package/_site/_test/integration-status-scan-test.js +29 -29
- package/_site/_test/kb-framework-test.js +57 -57
- package/_site/_test/kbpath-follow-test.js +63 -63
- package/_site/_test/knowledge-db-test.js +144 -144
- package/_site/_test/knowledge-engine-client-test.js +109 -109
- package/_site/_test/knowledge-maintenance-test.js +40 -40
- package/_site/_test/knowledge-panel-ui-contract-test.js +112 -0
- package/_site/_test/knowledge-scopes-test.js +37 -37
- package/_site/_test/knowledge-storage-location-test.js +28 -28
- package/_site/_test/launcher-readiness-test.js +80 -80
- package/_site/_test/legacy-claude-session-alias-test.js +106 -106
- package/_site/_test/legacy-routes-removed-test.js +47 -47
- package/_site/_test/legacy-workbench-exclusion-test.js +92 -92
- package/_site/_test/live-gateway-test.js +48 -48
- package/_site/_test/local-marketplace-test.js +16 -16
- package/_site/_test/log-redaction-test.js +58 -58
- package/_site/_test/markdown-maintenance-test.js +11 -11
- package/_site/_test/model-context-windows-test.js +89 -89
- package/_site/_test/module-agent-start-proxy-test.js +65 -65
- package/_site/_test/module-artifact-integrity-test.js +27 -27
- package/_site/_test/module-boundary-test.js +30 -30
- package/_site/_test/module-bridge-eventbridge-test.js +202 -202
- package/_site/_test/module-dynamic-port-test.js +118 -118
- package/_site/_test/module-index-proxy-test.js +33 -33
- package/_site/_test/module-model-configuration-test.js +44 -44
- package/_site/_test/module-process-lifecycle-test.js +35 -35
- package/_site/_test/module-stream-proxy-test.js +34 -34
- package/_site/_test/module-terminal-restart-test.js +63 -63
- package/_site/_test/module-wiring-unbind-race-test.js +59 -59
- package/_site/_test/native-context-integrations-test.js +86 -86
- package/_site/_test/orphaned-claim-recovery-test.js +80 -80
- package/_site/_test/package-boundary-test.js +43 -42
- package/_site/_test/package-startup-test.js +56 -56
- package/_site/_test/packaged-ui-smoke-test.js +88 -88
- package/_site/_test/pr-consumer-contract-test.js +55 -55
- package/_site/_test/product-brand-contract-test.js +25 -25
- package/_site/_test/product-diagnostics-ui-test.js +93 -93
- package/_site/_test/product-import-ui-test.js +104 -104
- package/_site/_test/product-progress-status-test.js +12 -1
- package/_site/_test/project-remove-running-guard-test.js +79 -79
- package/_site/_test/project-store-test.js +90 -90
- package/_site/_test/registry-events-test.js +38 -38
- package/_site/_test/release-version-sync-test.js +115 -115
- package/_site/_test/requirement-binding-test.js +113 -113
- package/_site/_test/runtime-endpoint-test.js +64 -64
- package/_site/_test/scanner-test.js +83 -83
- package/_site/_test/server-security-test.js +96 -96
- package/_site/_test/sessions-stream-test.js +93 -93
- package/_site/_test/shared-scope-root-binding-test.js +67 -67
- package/_site/_test/simple-import-test.js +98 -98
- package/_site/_test/startup-analysis-disabled-test.js +6 -6
- package/_site/_test/team-knowledge-store-sparse-checkout-test.js +196 -196
- package/_site/_test/team-knowledge-store-test.js +132 -132
- package/_site/_test/test-server-cleanup-test.js +35 -35
- package/_site/_test/test-server-module-isolation-test.js +37 -37
- package/_site/_test/tracking-start-test.js +35 -35
- package/_site/_test/workbench-context-receipts-test.js +22 -22
- package/_site/_test/workspace-ui-contract-test.js +31 -31
- package/_site/_test/zcode-capture-integration-test.js +108 -108
- package/_site/lib/ai-vendor-presets.js +83 -83
- package/_site/lib/ai-workspace.js +3 -3
- package/_site/lib/atomic-file.js +204 -204
- package/_site/lib/bridge-adapter.js +260 -260
- package/_site/lib/capture-hook-config.js +108 -108
- package/_site/lib/claude-cli-runner.js +89 -89
- package/_site/lib/cli-instances.js +43 -43
- package/_site/lib/codex-context-status.js +17 -17
- package/_site/lib/codex-notify-config.js +193 -193
- package/_site/lib/commit-conversation-binder.js +12 -12
- package/_site/lib/commit-reconciler.js +38 -38
- package/_site/lib/context-pack-builder.js +299 -299
- package/_site/lib/conversation-exclusions.js +204 -204
- package/_site/lib/conversation-query-service.js +17 -17
- package/_site/lib/data-dir.js +13 -13
- package/_site/lib/embedding-service.js +85 -85
- package/_site/lib/engine-connection.js +93 -93
- package/_site/lib/engine-knowledge-client.js +72 -72
- package/_site/lib/folder-picker-output.js +3 -3
- package/_site/lib/git-path.js +14 -14
- package/_site/lib/github-team-store.js +3 -3
- package/_site/lib/index-builder.js +157 -157
- package/_site/lib/integration-status-scan.js +99 -99
- package/_site/lib/integration-status-worker.js +14 -14
- package/_site/lib/kb-framework.js +15 -15
- package/_site/lib/knowledge-db.js +363 -363
- package/_site/lib/knowledge-schema.js +121 -121
- package/_site/lib/live-gateway.js +78 -78
- package/_site/lib/llm-client.js +12 -12
- package/_site/lib/model-context-windows.js +82 -82
- package/_site/lib/module-bridge.js +874 -874
- package/_site/lib/module-port-resolver.js +57 -57
- package/_site/lib/post-commit-automation.js +54 -54
- package/_site/lib/product-data.js +35 -35
- package/_site/lib/project-lifecycle-service.js +14 -14
- package/_site/lib/project-registry-store.js +129 -129
- package/_site/lib/prompt-registry.js +148 -148
- package/_site/lib/registry-events.js +16 -16
- package/_site/lib/requirement-adapters.js +10 -10
- package/_site/lib/requirement-binder.js +112 -112
- package/_site/lib/runtime-control.js +89 -89
- package/_site/lib/runtime-endpoint.js +5 -5
- package/_site/lib/zcode-context-integration.js +60 -60
- package/_site/scripts/codex-notify-fanout.cjs +95 -95
- package/_site/scripts/install-module-candidates.js +69 -69
- package/_site/scripts/pack-module-candidates.js +89 -89
- package/_site/scripts/sync-product-content.js +28 -28
- package/_site/scripts/sync-release-version.js +164 -164
- package/_site/scripts/vendor-modules.js +49 -49
- package/_site/scripts/verify-module-runtime.js +50 -50
- package/_site/scripts/verify-product-runtime.js +36 -36
- package/_site/scripts/verify-retrieval-gold.js +83 -83
- package/_site/server.js +15 -15
- package/_site/start.bat +26 -26
- package/_site/stop.bat +11 -11
- package/bin/project-knowledge-integrations.js +254 -254
- package/bin/project-knowledge-kb.js +67 -67
- package/bin/project-knowledge-mcp.js +8 -8
- package/bin/project-knowledge.js +170 -170
- package/claude-prompts.json +21 -21
- package/docs/README.zh-CN.md +205 -205
- package/docs/assets/architecture.svg +181 -181
- package/docs/assets/logo.svg +49 -49
- package/docs/fresh-v5-start.md +42 -42
- package/docs/leader-glm-workbench-playbook.md +122 -122
- package/docs/project-registry-schema.md +11 -11
- package/docs/release-5.0.16-acceptance.md +176 -176
- package/docs/release-5.0.17-acceptance.md +117 -117
- package/docs/release-5.0.19-acceptance.md +39 -25
- package/docs/team-knowledge-mode-a-plan.md +73 -73
- package/module-runtime-manifest.json +53 -33
- package/package.json +3 -2
- package/plugins/project-knowledge/.claude-plugin/plugin.json +1 -1
- package/plugins/project-knowledge/.codex-plugin/plugin.json +1 -1
- package/plugins/project-knowledge/.mcp.json +1 -1
- package/plugins/project-knowledge/opencode/project-knowledge.md +3 -3
- package/plugins/project-knowledge/skills/project-knowledge/SKILL.md +28 -28
- package/templates/change.md +30 -30
- package/templates/project-readme.md +18 -18
- package/ui/index.html +1 -1
- package/ui/knowledge-panel.html +118 -0
- package/ui/product.css +8 -0
- package/ui/product.js +146 -4
- package/vendor-manifest.json +55 -54
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
const assert = require('assert');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const os = require('os');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { SCHEMAS } = require('../lib/contracts');
|
|
6
|
-
const { StorageLayout } = require('../lib/storage-layout');
|
|
7
|
-
const { ProjectRegistryStore } = require('../lib/project-registry-store');
|
|
8
|
-
const { ProjectStore } = require('../lib/project-store');
|
|
9
|
-
|
|
10
|
-
(async () => {
|
|
11
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'pk-project-store-'));
|
|
12
|
-
const layout = new StorageLayout({ dataDir: root });
|
|
13
|
-
const registry = new ProjectRegistryStore({ layout });
|
|
14
|
-
const projects = new ProjectStore({ layout });
|
|
15
|
-
await registry.initialize();
|
|
16
|
-
|
|
17
|
-
const create = id => projects.create(id, {
|
|
18
|
-
displayName: id,
|
|
19
|
-
storageName: `${id}-stable`,
|
|
20
|
-
repoPath: path.join(root, 'repos', id),
|
|
21
|
-
knowledgePath: path.join(root, 'knowledge', id),
|
|
22
|
-
}, { trackingStartCommit: 'base' });
|
|
23
|
-
await Promise.all([create('project-a'), create('project-b')]);
|
|
24
|
-
await Promise.all([
|
|
25
|
-
registry.add('project-a', { displayName: 'A' }),
|
|
26
|
-
registry.add('project-b', { displayName: 'B' }),
|
|
27
|
-
]);
|
|
28
|
-
assert.deepStrictEqual(new Set(registry.listIds()), new Set(['project-a', 'project-b']));
|
|
29
|
-
|
|
30
|
-
await Promise.all([
|
|
31
|
-
projects.updateState('project-a', state => { state.lastAnalyzedCommit = 'commit-a'; }),
|
|
32
|
-
projects.updateState('project-b', state => { state.lastAnalyzedCommit = 'commit-b'; }),
|
|
33
|
-
]);
|
|
34
|
-
assert.strictEqual(projects.readState('project-a').lastAnalyzedCommit, 'commit-a');
|
|
35
|
-
assert.strictEqual(projects.readState('project-b').lastAnalyzedCommit, 'commit-b');
|
|
36
|
-
|
|
37
|
-
const order = [];
|
|
38
|
-
await Promise.all([
|
|
39
|
-
projects.updateState('project-a', async state => {
|
|
40
|
-
order.push('first-start');
|
|
41
|
-
await new Promise(resolve => setTimeout(resolve, 40));
|
|
42
|
-
order.push('first-end');
|
|
43
|
-
state.lastAnalyzedCommit = 'commit-a-2';
|
|
44
|
-
}),
|
|
45
|
-
projects.updateState('project-a', state => {
|
|
46
|
-
order.push('second');
|
|
47
|
-
state.lastAnalyzedCommit = 'commit-a-3';
|
|
48
|
-
}),
|
|
49
|
-
]);
|
|
50
|
-
assert.deepStrictEqual(order, ['first-start', 'first-end', 'second']);
|
|
51
|
-
assert.strictEqual(projects.readState('project-a').lastAnalyzedCommit, 'commit-a-3');
|
|
52
|
-
const revision = projects.readState('project-a').revision;
|
|
53
|
-
await assert.rejects(
|
|
54
|
-
projects.updateState('project-a', state => state, { expectedRevision: revision - 1 }),
|
|
55
|
-
error => error.code === 'PROJECT_BUSY',
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const configBefore = projects.readConfig('project-a');
|
|
59
|
-
const renamed = await projects.updateConfig('project-a', { displayName: 'Renamed A' });
|
|
60
|
-
assert.strictEqual(renamed.projectId, configBefore.projectId);
|
|
61
|
-
assert.strictEqual(renamed.storageName, configBefore.storageName);
|
|
62
|
-
assert.strictEqual(renamed.knowledgePath, configBefore.knowledgePath);
|
|
63
|
-
await assert.rejects(projects.updateConfig('project-a', { repoPath: path.join(root, 'unverified-move') }), error => error.code === 'INVALID_ARGUMENT');
|
|
64
|
-
const moved = await projects.updateConfig('project-a', { repoPath: path.join(root, 'verified-move') }, { allowRepoPath: true });
|
|
65
|
-
assert.strictEqual(moved.repoPath, path.resolve(root, 'verified-move'));
|
|
66
|
-
await assert.rejects(projects.updateConfig('project-a', { knowledgePath: path.join(root, 'other') }), error => error.code === 'IMMUTABLE_FIELD');
|
|
67
|
-
|
|
68
|
-
const requirementPath = layout.getProjectRequirementsPath('project-a');
|
|
69
|
-
assert.strictEqual(fs.existsSync(requirementPath), false);
|
|
70
|
-
await Promise.all(Array.from({ length: 20 }, (_, index) => projects.appendRequirement('project-a', {
|
|
71
|
-
schema: SCHEMAS.requirement,
|
|
72
|
-
id: `req-${index}`,
|
|
73
|
-
ts: new Date().toISOString(),
|
|
74
|
-
projectId: 'project-a',
|
|
75
|
-
requirement: `requirement ${index}`,
|
|
76
|
-
})));
|
|
77
|
-
assert.strictEqual(projects.readRequirements('project-a').length, 20);
|
|
78
|
-
assert.strictEqual(fs.existsSync(layout.getProjectRequirementsPath('project-b')), false);
|
|
79
|
-
|
|
80
|
-
fs.writeFileSync(layout.getProjectStatePath('project-b'), '{broken', 'utf8');
|
|
81
|
-
assert.throws(() => projects.readState('project-b'), error => error.code === 'DATA_CORRUPT');
|
|
82
|
-
|
|
83
|
-
const registryData = registry.read();
|
|
84
|
-
assert.deepStrictEqual(Object.keys(registryData.projects).sort(), ['project-a', 'project-b']);
|
|
85
|
-
assert.strictEqual(Object.prototype.hasOwnProperty.call(registryData.projects['project-a'], 'lastAnalyzedCommit'), false);
|
|
86
|
-
console.log('project-store-test PASS');
|
|
87
|
-
})().catch(error => {
|
|
88
|
-
console.error(error.stack || error.message);
|
|
89
|
-
process.exitCode = 1;
|
|
90
|
-
});
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { SCHEMAS } = require('../lib/contracts');
|
|
6
|
+
const { StorageLayout } = require('../lib/storage-layout');
|
|
7
|
+
const { ProjectRegistryStore } = require('../lib/project-registry-store');
|
|
8
|
+
const { ProjectStore } = require('../lib/project-store');
|
|
9
|
+
|
|
10
|
+
(async () => {
|
|
11
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'pk-project-store-'));
|
|
12
|
+
const layout = new StorageLayout({ dataDir: root });
|
|
13
|
+
const registry = new ProjectRegistryStore({ layout });
|
|
14
|
+
const projects = new ProjectStore({ layout });
|
|
15
|
+
await registry.initialize();
|
|
16
|
+
|
|
17
|
+
const create = id => projects.create(id, {
|
|
18
|
+
displayName: id,
|
|
19
|
+
storageName: `${id}-stable`,
|
|
20
|
+
repoPath: path.join(root, 'repos', id),
|
|
21
|
+
knowledgePath: path.join(root, 'knowledge', id),
|
|
22
|
+
}, { trackingStartCommit: 'base' });
|
|
23
|
+
await Promise.all([create('project-a'), create('project-b')]);
|
|
24
|
+
await Promise.all([
|
|
25
|
+
registry.add('project-a', { displayName: 'A' }),
|
|
26
|
+
registry.add('project-b', { displayName: 'B' }),
|
|
27
|
+
]);
|
|
28
|
+
assert.deepStrictEqual(new Set(registry.listIds()), new Set(['project-a', 'project-b']));
|
|
29
|
+
|
|
30
|
+
await Promise.all([
|
|
31
|
+
projects.updateState('project-a', state => { state.lastAnalyzedCommit = 'commit-a'; }),
|
|
32
|
+
projects.updateState('project-b', state => { state.lastAnalyzedCommit = 'commit-b'; }),
|
|
33
|
+
]);
|
|
34
|
+
assert.strictEqual(projects.readState('project-a').lastAnalyzedCommit, 'commit-a');
|
|
35
|
+
assert.strictEqual(projects.readState('project-b').lastAnalyzedCommit, 'commit-b');
|
|
36
|
+
|
|
37
|
+
const order = [];
|
|
38
|
+
await Promise.all([
|
|
39
|
+
projects.updateState('project-a', async state => {
|
|
40
|
+
order.push('first-start');
|
|
41
|
+
await new Promise(resolve => setTimeout(resolve, 40));
|
|
42
|
+
order.push('first-end');
|
|
43
|
+
state.lastAnalyzedCommit = 'commit-a-2';
|
|
44
|
+
}),
|
|
45
|
+
projects.updateState('project-a', state => {
|
|
46
|
+
order.push('second');
|
|
47
|
+
state.lastAnalyzedCommit = 'commit-a-3';
|
|
48
|
+
}),
|
|
49
|
+
]);
|
|
50
|
+
assert.deepStrictEqual(order, ['first-start', 'first-end', 'second']);
|
|
51
|
+
assert.strictEqual(projects.readState('project-a').lastAnalyzedCommit, 'commit-a-3');
|
|
52
|
+
const revision = projects.readState('project-a').revision;
|
|
53
|
+
await assert.rejects(
|
|
54
|
+
projects.updateState('project-a', state => state, { expectedRevision: revision - 1 }),
|
|
55
|
+
error => error.code === 'PROJECT_BUSY',
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const configBefore = projects.readConfig('project-a');
|
|
59
|
+
const renamed = await projects.updateConfig('project-a', { displayName: 'Renamed A' });
|
|
60
|
+
assert.strictEqual(renamed.projectId, configBefore.projectId);
|
|
61
|
+
assert.strictEqual(renamed.storageName, configBefore.storageName);
|
|
62
|
+
assert.strictEqual(renamed.knowledgePath, configBefore.knowledgePath);
|
|
63
|
+
await assert.rejects(projects.updateConfig('project-a', { repoPath: path.join(root, 'unverified-move') }), error => error.code === 'INVALID_ARGUMENT');
|
|
64
|
+
const moved = await projects.updateConfig('project-a', { repoPath: path.join(root, 'verified-move') }, { allowRepoPath: true });
|
|
65
|
+
assert.strictEqual(moved.repoPath, path.resolve(root, 'verified-move'));
|
|
66
|
+
await assert.rejects(projects.updateConfig('project-a', { knowledgePath: path.join(root, 'other') }), error => error.code === 'IMMUTABLE_FIELD');
|
|
67
|
+
|
|
68
|
+
const requirementPath = layout.getProjectRequirementsPath('project-a');
|
|
69
|
+
assert.strictEqual(fs.existsSync(requirementPath), false);
|
|
70
|
+
await Promise.all(Array.from({ length: 20 }, (_, index) => projects.appendRequirement('project-a', {
|
|
71
|
+
schema: SCHEMAS.requirement,
|
|
72
|
+
id: `req-${index}`,
|
|
73
|
+
ts: new Date().toISOString(),
|
|
74
|
+
projectId: 'project-a',
|
|
75
|
+
requirement: `requirement ${index}`,
|
|
76
|
+
})));
|
|
77
|
+
assert.strictEqual(projects.readRequirements('project-a').length, 20);
|
|
78
|
+
assert.strictEqual(fs.existsSync(layout.getProjectRequirementsPath('project-b')), false);
|
|
79
|
+
|
|
80
|
+
fs.writeFileSync(layout.getProjectStatePath('project-b'), '{broken', 'utf8');
|
|
81
|
+
assert.throws(() => projects.readState('project-b'), error => error.code === 'DATA_CORRUPT');
|
|
82
|
+
|
|
83
|
+
const registryData = registry.read();
|
|
84
|
+
assert.deepStrictEqual(Object.keys(registryData.projects).sort(), ['project-a', 'project-b']);
|
|
85
|
+
assert.strictEqual(Object.prototype.hasOwnProperty.call(registryData.projects['project-a'], 'lastAnalyzedCommit'), false);
|
|
86
|
+
console.log('project-store-test PASS');
|
|
87
|
+
})().catch(error => {
|
|
88
|
+
console.error(error.stack || error.message);
|
|
89
|
+
process.exitCode = 1;
|
|
90
|
+
});
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const assert = require('node:assert/strict');
|
|
3
|
-
const http = require('node:http');
|
|
4
|
-
const { RegistryEvents } = require('../lib/registry-events');
|
|
5
|
-
const { createRequestHandler } = require('../lib/server-app');
|
|
6
|
-
|
|
7
|
-
(async () => {
|
|
8
|
-
const events = new RegistryEvents(), received = [];
|
|
9
|
-
const off = events.subscribe(event => received.push(event));
|
|
10
|
-
assert.equal(received[0].type, 'registry-snapshot');
|
|
11
|
-
const runtime = { registryEvents: events, logger: { debug: async () => {}, info: async () => {} },
|
|
12
|
-
moduleBridge: { syncEngineConfiguration: async () => ({}) },
|
|
13
|
-
settingsStore: { read: () => ({ brain: { id: 'brain-default', name: 'before' }, knowledge: { rootPath: '' } }), updatePatch: async patch => ({ brain: patch.brain }) } };
|
|
14
|
-
// Exercise the real HTTP completion hook independently of business stores.
|
|
15
|
-
const handler = createRequestHandler(runtime, { host: '127.0.0.1', port: 0 });
|
|
16
|
-
const server = http.createServer(handler);
|
|
17
|
-
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
|
|
18
|
-
try {
|
|
19
|
-
const base = `http://127.0.0.1:${server.address().port}`;
|
|
20
|
-
const reader = await fetch(`${base}/api/registry/events`);
|
|
21
|
-
const stream = reader.body.getReader();
|
|
22
|
-
const first = new TextDecoder().decode((await stream.read()).value);
|
|
23
|
-
assert.match(first, /registry-snapshot/);
|
|
24
|
-
const mutation = await fetch(`${base}/api/brain`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'after' }) });
|
|
25
|
-
assert.equal(mutation.status, 200);
|
|
26
|
-
const change = new TextDecoder().decode((await stream.read()).value);
|
|
27
|
-
assert.match(change, /registry-changed/);
|
|
28
|
-
assert.equal(received[1].revision, 1);
|
|
29
|
-
const reconnect = []; events.subscribe(event => reconnect.push(event))();
|
|
30
|
-
assert.equal(reconnect[0].revision, 1);
|
|
31
|
-
assert.equal(reconnect[0].instanceId, received[0].instanceId);
|
|
32
|
-
await stream.cancel();
|
|
33
|
-
off(); events.publish(['brain']);
|
|
34
|
-
assert.equal(received.length, 2, 'unsubscribed observers receive no more updates');
|
|
35
|
-
assert.notEqual(new RegistryEvents().instanceId, events.instanceId, 'restart makes old revisions distinguishable');
|
|
36
|
-
console.log('registry-events-test PASS (real SSE, reconnect identity and unsubscribe)');
|
|
37
|
-
} finally { server.closeAllConnections(); await new Promise(resolve => server.close(resolve)); }
|
|
38
|
-
})().catch(error => { console.error(error); process.exitCode = 1; });
|
|
1
|
+
'use strict';
|
|
2
|
+
const assert = require('node:assert/strict');
|
|
3
|
+
const http = require('node:http');
|
|
4
|
+
const { RegistryEvents } = require('../lib/registry-events');
|
|
5
|
+
const { createRequestHandler } = require('../lib/server-app');
|
|
6
|
+
|
|
7
|
+
(async () => {
|
|
8
|
+
const events = new RegistryEvents(), received = [];
|
|
9
|
+
const off = events.subscribe(event => received.push(event));
|
|
10
|
+
assert.equal(received[0].type, 'registry-snapshot');
|
|
11
|
+
const runtime = { registryEvents: events, logger: { debug: async () => {}, info: async () => {} },
|
|
12
|
+
moduleBridge: { syncEngineConfiguration: async () => ({}) },
|
|
13
|
+
settingsStore: { read: () => ({ brain: { id: 'brain-default', name: 'before' }, knowledge: { rootPath: '' } }), updatePatch: async patch => ({ brain: patch.brain }) } };
|
|
14
|
+
// Exercise the real HTTP completion hook independently of business stores.
|
|
15
|
+
const handler = createRequestHandler(runtime, { host: '127.0.0.1', port: 0 });
|
|
16
|
+
const server = http.createServer(handler);
|
|
17
|
+
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
|
|
18
|
+
try {
|
|
19
|
+
const base = `http://127.0.0.1:${server.address().port}`;
|
|
20
|
+
const reader = await fetch(`${base}/api/registry/events`);
|
|
21
|
+
const stream = reader.body.getReader();
|
|
22
|
+
const first = new TextDecoder().decode((await stream.read()).value);
|
|
23
|
+
assert.match(first, /registry-snapshot/);
|
|
24
|
+
const mutation = await fetch(`${base}/api/brain`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'after' }) });
|
|
25
|
+
assert.equal(mutation.status, 200);
|
|
26
|
+
const change = new TextDecoder().decode((await stream.read()).value);
|
|
27
|
+
assert.match(change, /registry-changed/);
|
|
28
|
+
assert.equal(received[1].revision, 1);
|
|
29
|
+
const reconnect = []; events.subscribe(event => reconnect.push(event))();
|
|
30
|
+
assert.equal(reconnect[0].revision, 1);
|
|
31
|
+
assert.equal(reconnect[0].instanceId, received[0].instanceId);
|
|
32
|
+
await stream.cancel();
|
|
33
|
+
off(); events.publish(['brain']);
|
|
34
|
+
assert.equal(received.length, 2, 'unsubscribed observers receive no more updates');
|
|
35
|
+
assert.notEqual(new RegistryEvents().instanceId, events.instanceId, 'restart makes old revisions distinguishable');
|
|
36
|
+
console.log('registry-events-test PASS (real SSE, reconnect identity and unsubscribe)');
|
|
37
|
+
} finally { server.closeAllConnections(); await new Promise(resolve => server.close(resolve)); }
|
|
38
|
+
})().catch(error => { console.error(error); process.exitCode = 1; });
|
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
const assert = require('assert');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const os = require('os');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { spawnSync } = require('child_process');
|
|
6
|
-
|
|
7
|
-
const ROOT = path.resolve(__dirname, '..', '..');
|
|
8
|
-
const SCRIPT = path.join(ROOT, '_site', 'scripts', 'sync-release-version.js');
|
|
9
|
-
const TEMP = fs.mkdtempSync(path.join(os.tmpdir(), `project-knowledge-release-version-${process.pid}-`));
|
|
10
|
-
const FILES = [
|
|
11
|
-
'package.json',
|
|
12
|
-
'package-lock.json',
|
|
13
|
-
'desktop/package.json',
|
|
14
|
-
'desktop/package-lock.json',
|
|
15
|
-
'plugins/project-knowledge/.claude-plugin/plugin.json',
|
|
16
|
-
'plugins/project-knowledge/.codex-plugin/plugin.json',
|
|
17
|
-
'.claude-plugin/marketplace.json',
|
|
18
|
-
'plugins/project-knowledge/.mcp.json',
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
function copyFixture() {
|
|
22
|
-
for (const relative of FILES) {
|
|
23
|
-
const destination = path.join(TEMP, relative);
|
|
24
|
-
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
25
|
-
fs.copyFileSync(path.join(ROOT, relative), destination);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function run(args) {
|
|
30
|
-
return spawnSync(process.execPath, [SCRIPT, '--root', TEMP, ...args], {
|
|
31
|
-
cwd: ROOT,
|
|
32
|
-
encoding: 'utf8',
|
|
33
|
-
windowsHide: true,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function git(args) {
|
|
38
|
-
const result = spawnSync('git', args, { cwd: TEMP, encoding: 'utf8', windowsHide: true });
|
|
39
|
-
assert.strictEqual(result.status, 0, result.stderr || result.stdout);
|
|
40
|
-
return result;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
copyFixture();
|
|
45
|
-
git(['init', '-q']);
|
|
46
|
-
git(['config', 'user.email', 'release-test@example.local']);
|
|
47
|
-
git(['config', 'user.name', 'Release Test']);
|
|
48
|
-
git(['add', '.']);
|
|
49
|
-
git(['commit', '-q', '-m', 'fixture']);
|
|
50
|
-
const rootPackage = path.join(TEMP, 'package.json');
|
|
51
|
-
const value = JSON.parse(fs.readFileSync(rootPackage, 'utf8'));
|
|
52
|
-
value.version = '9.8.7';
|
|
53
|
-
fs.writeFileSync(rootPackage, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
54
|
-
|
|
55
|
-
const before = run(['--check']);
|
|
56
|
-
assert.notStrictEqual(before.status, 0, 'check must fail before derived version files are synchronized');
|
|
57
|
-
assert.match(before.stderr, /out of sync/);
|
|
58
|
-
|
|
59
|
-
const sync = run(['--stage']);
|
|
60
|
-
assert.strictEqual(sync.status, 0, sync.stderr || sync.stdout);
|
|
61
|
-
const check = run(['--check']);
|
|
62
|
-
assert.strictEqual(check.status, 0, check.stderr || check.stdout);
|
|
63
|
-
const matchingTag = run(['--check', '--tag', 'v9.8.7']);
|
|
64
|
-
assert.strictEqual(matchingTag.status, 0, matchingTag.stderr || matchingTag.stdout);
|
|
65
|
-
const mismatchedTag = run(['--check', '--tag', 'v9.8.8']);
|
|
66
|
-
assert.notStrictEqual(mismatchedTag.status, 0, 'check must reject a tag that does not match package.json');
|
|
67
|
-
assert.match(mismatchedTag.stderr, /must match package version/);
|
|
68
|
-
|
|
69
|
-
const claude = JSON.parse(fs.readFileSync(path.join(TEMP, 'plugins/project-knowledge/.claude-plugin/plugin.json'), 'utf8'));
|
|
70
|
-
const codex = JSON.parse(fs.readFileSync(path.join(TEMP, 'plugins/project-knowledge/.codex-plugin/plugin.json'), 'utf8'));
|
|
71
|
-
const marketplace = JSON.parse(fs.readFileSync(path.join(TEMP, '.claude-plugin/marketplace.json'), 'utf8'));
|
|
72
|
-
const mcp = JSON.parse(fs.readFileSync(path.join(TEMP, 'plugins/project-knowledge/.mcp.json'), 'utf8'));
|
|
73
|
-
const desktopLock = JSON.parse(fs.readFileSync(path.join(TEMP, 'desktop/package-lock.json'), 'utf8'));
|
|
74
|
-
assert.strictEqual(claude.version, '9.8.7');
|
|
75
|
-
assert.strictEqual(codex.version, '9.8.7');
|
|
76
|
-
assert.strictEqual(marketplace.plugins[0].version, '9.8.7');
|
|
77
|
-
const server = mcp.mcpServers['project-knowledge'];
|
|
78
|
-
const serialized = JSON.stringify(server);
|
|
79
|
-
assert.strictEqual(server.command, 'node', 'the MCP server must bootstrap through the local node runtime');
|
|
80
|
-
assert.strictEqual(server.args[0], '-e', 'the MCP server must use the node -e bootstrap chain');
|
|
81
|
-
assert(server.args[1].includes('mcp-launcher.cjs'), 'the bootstrap must load the bundled local launcher');
|
|
82
|
-
assert(!/npx/i.test(serialized) && !/@sanqianx\/project-knowledge@/.test(serialized), 'the pinned npx package form must stay rejected');
|
|
83
|
-
assert(!/https?:\/\//.test(serialized), 'the MCP bootstrap must not reference network sources');
|
|
84
|
-
assert.strictEqual(server.cwd, undefined, 'the MCP server must not pin a cwd');
|
|
85
|
-
assert(!server.args[1].includes('process.cwd'), 'the MCP bootstrap must never fall back to cwd source resolution');
|
|
86
|
-
assert(server.env && server.env.KB_PLUGIN_VERSION === '9.8.7', 'env.KB_PLUGIN_VERSION must follow the release version');
|
|
87
|
-
assert.strictEqual(desktopLock.version, '9.8.7');
|
|
88
|
-
assert.strictEqual(desktopLock.packages[''].version, '9.8.7');
|
|
89
|
-
const staged = git(['diff', '--cached', '--name-only']);
|
|
90
|
-
const stagedFiles = staged.stdout.split(/\r?\n/).filter(Boolean).sort();
|
|
91
|
-
assert.deepStrictEqual(stagedFiles, [
|
|
92
|
-
'.claude-plugin/marketplace.json',
|
|
93
|
-
'desktop/package-lock.json',
|
|
94
|
-
'desktop/package.json',
|
|
95
|
-
'package-lock.json',
|
|
96
|
-
'plugins/project-knowledge/.claude-plugin/plugin.json',
|
|
97
|
-
'plugins/project-knowledge/.codex-plugin/plugin.json',
|
|
98
|
-
'plugins/project-knowledge/.mcp.json',
|
|
99
|
-
]);
|
|
100
|
-
const scripts = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).scripts;
|
|
101
|
-
assert.strictEqual(scripts.preversion, 'npm run release:verify');
|
|
102
|
-
assert.strictEqual(scripts.version, 'node _site/scripts/sync-release-version.js --stage --web-only');
|
|
103
|
-
assert.strictEqual(scripts.postversion, 'npm run release:verify');
|
|
104
|
-
const desktopBytes = FILES.filter(file => file.startsWith('desktop/')).map(file => fs.readFileSync(path.join(TEMP, file)));
|
|
105
|
-
value.version = '9.8.8-rc.1'; fs.writeFileSync(rootPackage, JSON.stringify(value, null, 2) + '\n');
|
|
106
|
-
assert.strictEqual(run(['--web-only']).status, 0);
|
|
107
|
-
assert.strictEqual(run(['--check', '--web-only']).status, 0);
|
|
108
|
-
const resyncedMcp = JSON.parse(fs.readFileSync(path.join(TEMP, 'plugins/project-knowledge/.mcp.json'), 'utf8'));
|
|
109
|
-
assert.strictEqual(resyncedMcp.mcpServers['project-knowledge'].env.KB_PLUGIN_VERSION, '9.8.8-rc.1', 'KB_PLUGIN_VERSION must follow every version bump');
|
|
110
|
-
assert.notStrictEqual(run(['--check']).status, 0, 'desktop still needs explicit synchronization for desktop releases');
|
|
111
|
-
FILES.filter(file => file.startsWith('desktop/')).forEach((file, i) => assert.deepStrictEqual(fs.readFileSync(path.join(TEMP, file)), desktopBytes[i]));
|
|
112
|
-
console.log('release-version-sync-test PASS');
|
|
113
|
-
} finally {
|
|
114
|
-
fs.rmSync(TEMP, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
115
|
-
}
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const ROOT = path.resolve(__dirname, '..', '..');
|
|
8
|
+
const SCRIPT = path.join(ROOT, '_site', 'scripts', 'sync-release-version.js');
|
|
9
|
+
const TEMP = fs.mkdtempSync(path.join(os.tmpdir(), `project-knowledge-release-version-${process.pid}-`));
|
|
10
|
+
const FILES = [
|
|
11
|
+
'package.json',
|
|
12
|
+
'package-lock.json',
|
|
13
|
+
'desktop/package.json',
|
|
14
|
+
'desktop/package-lock.json',
|
|
15
|
+
'plugins/project-knowledge/.claude-plugin/plugin.json',
|
|
16
|
+
'plugins/project-knowledge/.codex-plugin/plugin.json',
|
|
17
|
+
'.claude-plugin/marketplace.json',
|
|
18
|
+
'plugins/project-knowledge/.mcp.json',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function copyFixture() {
|
|
22
|
+
for (const relative of FILES) {
|
|
23
|
+
const destination = path.join(TEMP, relative);
|
|
24
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
25
|
+
fs.copyFileSync(path.join(ROOT, relative), destination);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function run(args) {
|
|
30
|
+
return spawnSync(process.execPath, [SCRIPT, '--root', TEMP, ...args], {
|
|
31
|
+
cwd: ROOT,
|
|
32
|
+
encoding: 'utf8',
|
|
33
|
+
windowsHide: true,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function git(args) {
|
|
38
|
+
const result = spawnSync('git', args, { cwd: TEMP, encoding: 'utf8', windowsHide: true });
|
|
39
|
+
assert.strictEqual(result.status, 0, result.stderr || result.stdout);
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
copyFixture();
|
|
45
|
+
git(['init', '-q']);
|
|
46
|
+
git(['config', 'user.email', 'release-test@example.local']);
|
|
47
|
+
git(['config', 'user.name', 'Release Test']);
|
|
48
|
+
git(['add', '.']);
|
|
49
|
+
git(['commit', '-q', '-m', 'fixture']);
|
|
50
|
+
const rootPackage = path.join(TEMP, 'package.json');
|
|
51
|
+
const value = JSON.parse(fs.readFileSync(rootPackage, 'utf8'));
|
|
52
|
+
value.version = '9.8.7';
|
|
53
|
+
fs.writeFileSync(rootPackage, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
54
|
+
|
|
55
|
+
const before = run(['--check']);
|
|
56
|
+
assert.notStrictEqual(before.status, 0, 'check must fail before derived version files are synchronized');
|
|
57
|
+
assert.match(before.stderr, /out of sync/);
|
|
58
|
+
|
|
59
|
+
const sync = run(['--stage']);
|
|
60
|
+
assert.strictEqual(sync.status, 0, sync.stderr || sync.stdout);
|
|
61
|
+
const check = run(['--check']);
|
|
62
|
+
assert.strictEqual(check.status, 0, check.stderr || check.stdout);
|
|
63
|
+
const matchingTag = run(['--check', '--tag', 'v9.8.7']);
|
|
64
|
+
assert.strictEqual(matchingTag.status, 0, matchingTag.stderr || matchingTag.stdout);
|
|
65
|
+
const mismatchedTag = run(['--check', '--tag', 'v9.8.8']);
|
|
66
|
+
assert.notStrictEqual(mismatchedTag.status, 0, 'check must reject a tag that does not match package.json');
|
|
67
|
+
assert.match(mismatchedTag.stderr, /must match package version/);
|
|
68
|
+
|
|
69
|
+
const claude = JSON.parse(fs.readFileSync(path.join(TEMP, 'plugins/project-knowledge/.claude-plugin/plugin.json'), 'utf8'));
|
|
70
|
+
const codex = JSON.parse(fs.readFileSync(path.join(TEMP, 'plugins/project-knowledge/.codex-plugin/plugin.json'), 'utf8'));
|
|
71
|
+
const marketplace = JSON.parse(fs.readFileSync(path.join(TEMP, '.claude-plugin/marketplace.json'), 'utf8'));
|
|
72
|
+
const mcp = JSON.parse(fs.readFileSync(path.join(TEMP, 'plugins/project-knowledge/.mcp.json'), 'utf8'));
|
|
73
|
+
const desktopLock = JSON.parse(fs.readFileSync(path.join(TEMP, 'desktop/package-lock.json'), 'utf8'));
|
|
74
|
+
assert.strictEqual(claude.version, '9.8.7');
|
|
75
|
+
assert.strictEqual(codex.version, '9.8.7');
|
|
76
|
+
assert.strictEqual(marketplace.plugins[0].version, '9.8.7');
|
|
77
|
+
const server = mcp.mcpServers['project-knowledge'];
|
|
78
|
+
const serialized = JSON.stringify(server);
|
|
79
|
+
assert.strictEqual(server.command, 'node', 'the MCP server must bootstrap through the local node runtime');
|
|
80
|
+
assert.strictEqual(server.args[0], '-e', 'the MCP server must use the node -e bootstrap chain');
|
|
81
|
+
assert(server.args[1].includes('mcp-launcher.cjs'), 'the bootstrap must load the bundled local launcher');
|
|
82
|
+
assert(!/npx/i.test(serialized) && !/@sanqianx\/project-knowledge@/.test(serialized), 'the pinned npx package form must stay rejected');
|
|
83
|
+
assert(!/https?:\/\//.test(serialized), 'the MCP bootstrap must not reference network sources');
|
|
84
|
+
assert.strictEqual(server.cwd, undefined, 'the MCP server must not pin a cwd');
|
|
85
|
+
assert(!server.args[1].includes('process.cwd'), 'the MCP bootstrap must never fall back to cwd source resolution');
|
|
86
|
+
assert(server.env && server.env.KB_PLUGIN_VERSION === '9.8.7', 'env.KB_PLUGIN_VERSION must follow the release version');
|
|
87
|
+
assert.strictEqual(desktopLock.version, '9.8.7');
|
|
88
|
+
assert.strictEqual(desktopLock.packages[''].version, '9.8.7');
|
|
89
|
+
const staged = git(['diff', '--cached', '--name-only']);
|
|
90
|
+
const stagedFiles = staged.stdout.split(/\r?\n/).filter(Boolean).sort();
|
|
91
|
+
assert.deepStrictEqual(stagedFiles, [
|
|
92
|
+
'.claude-plugin/marketplace.json',
|
|
93
|
+
'desktop/package-lock.json',
|
|
94
|
+
'desktop/package.json',
|
|
95
|
+
'package-lock.json',
|
|
96
|
+
'plugins/project-knowledge/.claude-plugin/plugin.json',
|
|
97
|
+
'plugins/project-knowledge/.codex-plugin/plugin.json',
|
|
98
|
+
'plugins/project-knowledge/.mcp.json',
|
|
99
|
+
]);
|
|
100
|
+
const scripts = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).scripts;
|
|
101
|
+
assert.strictEqual(scripts.preversion, 'npm run release:verify');
|
|
102
|
+
assert.strictEqual(scripts.version, 'node _site/scripts/sync-release-version.js --stage --web-only');
|
|
103
|
+
assert.strictEqual(scripts.postversion, 'npm run release:verify');
|
|
104
|
+
const desktopBytes = FILES.filter(file => file.startsWith('desktop/')).map(file => fs.readFileSync(path.join(TEMP, file)));
|
|
105
|
+
value.version = '9.8.8-rc.1'; fs.writeFileSync(rootPackage, JSON.stringify(value, null, 2) + '\n');
|
|
106
|
+
assert.strictEqual(run(['--web-only']).status, 0);
|
|
107
|
+
assert.strictEqual(run(['--check', '--web-only']).status, 0);
|
|
108
|
+
const resyncedMcp = JSON.parse(fs.readFileSync(path.join(TEMP, 'plugins/project-knowledge/.mcp.json'), 'utf8'));
|
|
109
|
+
assert.strictEqual(resyncedMcp.mcpServers['project-knowledge'].env.KB_PLUGIN_VERSION, '9.8.8-rc.1', 'KB_PLUGIN_VERSION must follow every version bump');
|
|
110
|
+
assert.notStrictEqual(run(['--check']).status, 0, 'desktop still needs explicit synchronization for desktop releases');
|
|
111
|
+
FILES.filter(file => file.startsWith('desktop/')).forEach((file, i) => assert.deepStrictEqual(fs.readFileSync(path.join(TEMP, file)), desktopBytes[i]));
|
|
112
|
+
console.log('release-version-sync-test PASS');
|
|
113
|
+
} finally {
|
|
114
|
+
fs.rmSync(TEMP, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
115
|
+
}
|