scene-capability-engine 3.6.65 → 3.6.67
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/CHANGELOG.md +16 -0
- package/README.md +17 -6
- package/README.zh.md +18 -6
- package/bin/scene-capability-engine.js +4 -0
- package/docs/README.md +2 -2
- package/docs/command-reference.md +382 -6
- package/docs/document-governance.md +3 -2
- package/docs/integration-modes.md +62 -478
- package/docs/integration-philosophy.md +56 -263
- package/docs/magicball-project-portfolio-contract.md +114 -2
- package/docs/project-management/README.md +14 -0
- package/docs/project-management/assurance/backup.md +3 -0
- package/docs/project-management/assurance/config.md +3 -0
- package/docs/project-management/assurance/evidence/README.md +3 -0
- package/docs/project-management/assurance/incidents/README.md +3 -0
- package/docs/project-management/assurance/logs.md +3 -0
- package/docs/project-management/assurance/overview.md +3 -0
- package/docs/project-management/assurance/recovery/README.md +3 -0
- package/docs/project-management/assurance/resource.md +3 -0
- package/docs/project-management/assurance/runbooks/README.md +3 -0
- package/docs/project-management/delivery/acceptance/README.md +3 -0
- package/docs/project-management/delivery/acceptance/evidence/README.md +3 -0
- package/docs/project-management/delivery/acceptance/exceptions/README.md +3 -0
- package/docs/project-management/delivery/acceptance/reports/README.md +3 -0
- package/docs/project-management/delivery/documents/changes.md +3 -0
- package/docs/project-management/delivery/documents/issues.md +3 -0
- package/docs/project-management/delivery/documents/overview.md +3 -0
- package/docs/project-management/delivery/documents/planning.md +3 -0
- package/docs/project-management/delivery/documents/requirements.md +3 -0
- package/docs/project-management/delivery/documents/tracking.md +3 -0
- package/docs/project-management/delivery/handoffs/README.md +3 -0
- package/docs/project-management/delivery/handoffs/evidence/README.md +3 -0
- package/docs/project-management/delivery/handoffs/records/README.md +3 -0
- package/docs/project-management/delivery/overview.md +10 -0
- package/docs/project-management/delivery/releases/README.md +3 -0
- package/docs/project-management/delivery/releases/baselines/README.md +3 -0
- package/docs/project-management/delivery/releases/evidence/README.md +3 -0
- package/docs/project-management/delivery/tables/changes.md +3 -0
- package/docs/project-management/delivery/tables/issues.md +3 -0
- package/docs/project-management/delivery/tables/planning.md +3 -0
- package/docs/project-management/delivery/tables/requirements.md +3 -0
- package/docs/project-management/delivery/tables/tracking.md +3 -0
- package/docs/project-management/environment/agent-discovery.md +3 -0
- package/docs/project-management/environment/development.md +3 -0
- package/docs/project-management/environment/overview.md +10 -0
- package/docs/project-management/environment/testing.md +3 -0
- package/docs/project-management/environment/version-alignment.md +3 -0
- package/docs/quick-start-with-ai-tools.md +68 -308
- package/docs/releases/README.md +2 -0
- package/docs/releases/v3.6.66.md +23 -0
- package/docs/releases/v3.6.67.md +23 -0
- package/docs/steering-governance.md +64 -2
- package/docs/zh/README.md +2 -2
- package/docs/zh/releases/README.md +2 -0
- package/docs/zh/releases/v3.6.66.md +23 -0
- package/docs/zh/releases/v3.6.67.md +23 -0
- package/lib/commands/adopt.js +24 -0
- package/lib/commands/native.js +158 -0
- package/lib/commands/project.js +95 -0
- package/lib/commands/semantic.js +1459 -0
- package/lib/commands/session.js +74 -3
- package/lib/commands/spec-bootstrap.js +10 -1
- package/lib/commands/spec-gate.js +10 -1
- package/lib/commands/spec-pipeline.js +10 -1
- package/lib/commands/studio.js +405 -30
- package/lib/commands/task.js +141 -7
- package/lib/governance/supreme-principles.js +530 -0
- package/lib/problem/problem-evaluator.js +4 -0
- package/lib/project/candidate-inspection-service.js +24 -1
- package/lib/project/portfolio-projection-service.js +315 -5
- package/lib/project/project-channel-output.js +94 -0
- package/lib/project/project-channel-projection.js +181 -0
- package/lib/project/root-onboarding-service.js +60 -8
- package/lib/project/semantic-shared-source-projection.js +150 -0
- package/lib/project/supervision-action-model.js +277 -0
- package/lib/project/supervision-projection-service.js +305 -5
- package/lib/project/target-resolution-service.js +70 -5
- package/lib/project/visibility-policy.js +93 -0
- package/lib/runtime/multi-spec-scene-session.js +8 -1
- package/lib/runtime/project-channel-context-store.js +387 -0
- package/lib/runtime/project-channel-context.js +406 -0
- package/lib/runtime/scene-session-binding.js +46 -0
- package/lib/runtime/session-store.js +186 -0
- package/lib/runtime/steering-contract.js +7 -1
- package/lib/semantic/archive-report.js +283 -0
- package/lib/semantic/archive-routing.js +67 -0
- package/lib/semantic/backflow-report.js +245 -0
- package/lib/semantic/capability-contract.js +30 -0
- package/lib/semantic/delta-export.js +145 -0
- package/lib/semantic/interaction-observer.js +254 -0
- package/lib/semantic/kernel-loader.js +881 -0
- package/lib/semantic/native-runtime.js +359 -0
- package/lib/semantic/progress-ledger.js +433 -0
- package/lib/semantic/replay-evaluator.js +382 -0
- package/lib/semantic/shared-publication.js +592 -0
- package/lib/semantic/shared-source-config.js +183 -0
- package/lib/semantic/shared-source-connect.js +139 -0
- package/lib/semantic/shared-source-discovery.js +98 -0
- package/lib/semantic/shared-sync-export.js +413 -0
- package/lib/semantic/shared-sync-intake.js +592 -0
- package/lib/semantic/shared-sync-merge.js +547 -0
- package/lib/semantic/shared-sync-release.js +463 -0
- package/lib/semantic/supreme-intent-report.js +300 -0
- package/lib/state/sce-state-store.js +1360 -0
- package/lib/steering/context-sync-manager.js +276 -25
- package/lib/studio/spec-intake-governor.js +39 -3
- package/lib/studio/task-envelope.js +35 -2
- package/lib/workspace/takeover-baseline.js +342 -83
- package/package.json +7 -2
- package/scripts/agent-governance-baseline-audit.js +395 -0
- package/scripts/clarification-first-audit.js +9 -9
- package/scripts/deprecated-entry-audit.js +240 -0
- package/scripts/release-posture-report.js +262 -0
- package/template/.sce/README.md +62 -228
- package/template/.sce/config/semantic-shared-sources.json +5 -0
- package/template/.sce/config/supreme-principles-policy.json +105 -0
- package/template/.sce/config/takeover-baseline.json +7 -0
- package/template/.sce/steering/CORE_PRINCIPLES.md +23 -63
- package/template/.sce/steering/CURRENT_CONTEXT.md +4 -0
- package/template/.sce/steering/RULES_GUIDE.md +17 -9
- package/template/README.md +32 -96
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const {
|
|
4
|
+
SEMANTIC_SHARED_SOURCE_CONFIG,
|
|
5
|
+
resolveSemanticSharedSourceConfigPath
|
|
6
|
+
} = require('./shared-sync-intake');
|
|
7
|
+
|
|
8
|
+
const SEMANTIC_SHARED_SOURCE_CONFIG_API_VERSION = 'sce.semantic.shared-source-config/v0.1';
|
|
9
|
+
|
|
10
|
+
function normalizeString(value) {
|
|
11
|
+
if (typeof value !== 'string') {
|
|
12
|
+
return '';
|
|
13
|
+
}
|
|
14
|
+
return value.trim();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function normalizeBoolean(value, fallback = true) {
|
|
18
|
+
if (typeof value === 'boolean') {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
const normalized = normalizeString(`${value || ''}`).toLowerCase();
|
|
22
|
+
if (!normalized) {
|
|
23
|
+
return fallback;
|
|
24
|
+
}
|
|
25
|
+
if (['1', 'true', 'yes', 'y', 'on'].includes(normalized)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
if (['0', 'false', 'no', 'n', 'off'].includes(normalized)) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return fallback;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isObject(value) {
|
|
35
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sanitizeSource(source = {}) {
|
|
39
|
+
if (!isObject(source)) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const bundle = normalizeString(source.bundle || source.source || source.url || source.file);
|
|
43
|
+
if (!bundle) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
name: normalizeString(source.name) || 'semantic-shared',
|
|
48
|
+
enabled: normalizeBoolean(source.enabled, true),
|
|
49
|
+
bundle,
|
|
50
|
+
root: normalizeString(source.root || source.base || source.base_url || source.base_path) || null,
|
|
51
|
+
required_release_state: normalizeString(source.required_release_state || source.requiredReleaseState) || null
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function toPayloadItems(sources = []) {
|
|
56
|
+
return sources
|
|
57
|
+
.map((item) => sanitizeSource(item))
|
|
58
|
+
.filter(Boolean)
|
|
59
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function loadSourceDescriptor(projectPath, inputFile = '', fileSystem = fs) {
|
|
63
|
+
const normalized = normalizeString(inputFile);
|
|
64
|
+
if (!normalized) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const absolutePath = path.isAbsolute(normalized)
|
|
68
|
+
? normalized
|
|
69
|
+
: path.resolve(projectPath, normalized);
|
|
70
|
+
if (!await fileSystem.pathExists(absolutePath)) {
|
|
71
|
+
throw new Error(`shared source descriptor not found: ${inputFile}`);
|
|
72
|
+
}
|
|
73
|
+
const payload = await fileSystem.readJson(absolutePath);
|
|
74
|
+
if (!isObject(payload) || !isObject(payload.source)) {
|
|
75
|
+
throw new Error(`invalid shared source descriptor: ${inputFile}`);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
descriptor_file: absolutePath,
|
|
79
|
+
descriptor: payload
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function readSemanticSharedSourceConfigForUpdate(projectPath, configPath = '', fileSystem = fs) {
|
|
84
|
+
const absoluteConfigPath = resolveSemanticSharedSourceConfigPath(projectPath, configPath || SEMANTIC_SHARED_SOURCE_CONFIG);
|
|
85
|
+
if (!await fileSystem.pathExists(absoluteConfigPath)) {
|
|
86
|
+
return {
|
|
87
|
+
config_file: absoluteConfigPath,
|
|
88
|
+
config: {
|
|
89
|
+
enabled: true,
|
|
90
|
+
mirror_root: '.sce/knowledge/semantic-shared',
|
|
91
|
+
sources: []
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const config = await fileSystem.readJson(absoluteConfigPath);
|
|
96
|
+
if (!isObject(config)) {
|
|
97
|
+
throw new Error(`semantic shared source config must be a JSON object: ${absoluteConfigPath}`);
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
config_file: absoluteConfigPath,
|
|
101
|
+
config: {
|
|
102
|
+
enabled: normalizeBoolean(config.enabled, true),
|
|
103
|
+
mirror_root: normalizeString(config.mirror_root) || '.sce/knowledge/semantic-shared',
|
|
104
|
+
sources: Array.isArray(config.sources) ? config.sources : []
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function listSemanticSharedSources(options = {}, dependencies = {}) {
|
|
110
|
+
const projectPath = dependencies.projectPath || process.cwd();
|
|
111
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
112
|
+
const { config_file, config } = await readSemanticSharedSourceConfigForUpdate(projectPath, options.config, fileSystem);
|
|
113
|
+
const items = toPayloadItems(config.sources);
|
|
114
|
+
return {
|
|
115
|
+
api_version: SEMANTIC_SHARED_SOURCE_CONFIG_API_VERSION,
|
|
116
|
+
mode: 'semantic-list-shared-sources',
|
|
117
|
+
success: true,
|
|
118
|
+
enabled: normalizeBoolean(config.enabled, true),
|
|
119
|
+
mirror_root: normalizeString(config.mirror_root) || '.sce/knowledge/semantic-shared',
|
|
120
|
+
config_file,
|
|
121
|
+
total: items.length,
|
|
122
|
+
items
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function upsertSemanticSharedSource(options = {}, dependencies = {}) {
|
|
127
|
+
const projectPath = dependencies.projectPath || process.cwd();
|
|
128
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
129
|
+
const { config_file, config } = await readSemanticSharedSourceConfigForUpdate(projectPath, options.config, fileSystem);
|
|
130
|
+
const descriptorPayload = await loadSourceDescriptor(projectPath, options.inputFile || options.input_file, fileSystem);
|
|
131
|
+
const descriptorSource = descriptorPayload && descriptorPayload.descriptor && descriptorPayload.descriptor.source;
|
|
132
|
+
const name = normalizeString(options.name) || normalizeString(descriptorSource && descriptorSource.name);
|
|
133
|
+
const bundle = normalizeString(options.bundle || options.source || options.url || options.file)
|
|
134
|
+
|| normalizeString(descriptorSource && descriptorSource.bundle);
|
|
135
|
+
if (!name) {
|
|
136
|
+
throw new Error('shared source name is required');
|
|
137
|
+
}
|
|
138
|
+
if (!bundle) {
|
|
139
|
+
throw new Error('shared source bundle is required');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const nextSource = sanitizeSource({
|
|
143
|
+
name,
|
|
144
|
+
enabled: options.enabled ?? (descriptorSource && descriptorSource.enabled),
|
|
145
|
+
bundle,
|
|
146
|
+
root: options.root || (descriptorSource && descriptorSource.root),
|
|
147
|
+
required_release_state: options.requiredReleaseState || options.required_release_state || (descriptorSource && descriptorSource.required_release_state)
|
|
148
|
+
});
|
|
149
|
+
if (!nextSource) {
|
|
150
|
+
throw new Error('failed to normalize shared source configuration');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const existingSources = toPayloadItems(config.sources);
|
|
154
|
+
const nextSources = existingSources.filter((item) => item.name !== nextSource.name);
|
|
155
|
+
nextSources.push(nextSource);
|
|
156
|
+
nextSources.sort((left, right) => left.name.localeCompare(right.name));
|
|
157
|
+
|
|
158
|
+
const nextConfig = {
|
|
159
|
+
enabled: normalizeBoolean(config.enabled, true),
|
|
160
|
+
mirror_root: normalizeString(config.mirror_root) || '.sce/knowledge/semantic-shared',
|
|
161
|
+
sources: nextSources
|
|
162
|
+
};
|
|
163
|
+
await fileSystem.ensureDir(require('path').dirname(config_file));
|
|
164
|
+
await fileSystem.writeJson(config_file, nextConfig, { spaces: 2 });
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
api_version: SEMANTIC_SHARED_SOURCE_CONFIG_API_VERSION,
|
|
168
|
+
mode: 'semantic-set-shared-source',
|
|
169
|
+
success: true,
|
|
170
|
+
config_file,
|
|
171
|
+
descriptor_file: descriptorPayload ? descriptorPayload.descriptor_file : null,
|
|
172
|
+
source: nextSource,
|
|
173
|
+
total: nextSources.length,
|
|
174
|
+
items: nextSources
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
module.exports = {
|
|
179
|
+
SEMANTIC_SHARED_SOURCE_CONFIG_API_VERSION,
|
|
180
|
+
loadSourceDescriptor,
|
|
181
|
+
listSemanticSharedSources,
|
|
182
|
+
upsertSemanticSharedSource
|
|
183
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const { loadSourceDescriptor, upsertSemanticSharedSource } = require('./shared-source-config');
|
|
3
|
+
const { inspectSemanticSharedSource, syncSemanticSharedBundle } = require('./shared-sync-intake');
|
|
4
|
+
const { resolveDefaultSemanticSharedPublishedSourceDescriptorOutFile } = require('./shared-sync-release');
|
|
5
|
+
|
|
6
|
+
const SEMANTIC_SHARED_SOURCE_CONNECT_API_VERSION = 'sce.semantic.shared-source-connect/v0.1';
|
|
7
|
+
|
|
8
|
+
function normalizeString(value) {
|
|
9
|
+
if (typeof value !== 'string') {
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
return value.trim();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function normalizeBoolean(value, fallback = false) {
|
|
16
|
+
if (typeof value === 'boolean') {
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
const normalized = normalizeString(`${value || ''}`).toLowerCase();
|
|
20
|
+
if (!normalized) {
|
|
21
|
+
return fallback;
|
|
22
|
+
}
|
|
23
|
+
if (['1', 'true', 'yes', 'y', 'on'].includes(normalized)) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
if (['0', 'false', 'no', 'n', 'off'].includes(normalized)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return fallback;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readDescriptorReleaseState(descriptor = {}) {
|
|
33
|
+
if (!descriptor || typeof descriptor !== 'object') {
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
const publication = descriptor.publication && typeof descriptor.publication === 'object'
|
|
37
|
+
? descriptor.publication
|
|
38
|
+
: {};
|
|
39
|
+
return normalizeString(publication.release_state)
|
|
40
|
+
|| normalizeString(descriptor.source && descriptor.source.required_release_state);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function connectSemanticSharedSource(options = {}, dependencies = {}) {
|
|
44
|
+
const projectPath = dependencies.projectPath || process.cwd();
|
|
45
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
46
|
+
const specId = normalizeString(options.spec);
|
|
47
|
+
const descriptorInput = normalizeString(options.inputFile || options.input_file)
|
|
48
|
+
|| (specId ? resolveDefaultSemanticSharedPublishedSourceDescriptorOutFile(specId) : '');
|
|
49
|
+
if (!descriptorInput) {
|
|
50
|
+
throw new Error('shared source descriptor is required (use --input-file or provide --spec)');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const descriptorPayload = await loadSourceDescriptor(projectPath, descriptorInput, fileSystem);
|
|
54
|
+
const descriptor = descriptorPayload.descriptor;
|
|
55
|
+
const descriptorReleaseState = readDescriptorReleaseState(descriptor) || null;
|
|
56
|
+
const allowNonApproved = normalizeBoolean(options.allowNonApproved || options.allow_non_approved, false);
|
|
57
|
+
const blocked = [];
|
|
58
|
+
if (!allowNonApproved && descriptorReleaseState !== 'approved-central') {
|
|
59
|
+
blocked.push({
|
|
60
|
+
reason: 'descriptor-not-approved-central',
|
|
61
|
+
descriptor_release_state: descriptorReleaseState
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let registration = null;
|
|
66
|
+
let health = null;
|
|
67
|
+
let sync = null;
|
|
68
|
+
|
|
69
|
+
if (blocked.length === 0) {
|
|
70
|
+
registration = await upsertSemanticSharedSource({
|
|
71
|
+
inputFile: descriptorInput,
|
|
72
|
+
name: options.name,
|
|
73
|
+
bundle: options.bundle,
|
|
74
|
+
root: options.root,
|
|
75
|
+
enabled: options.enabled,
|
|
76
|
+
requiredReleaseState: options.requiredReleaseState || options.required_release_state,
|
|
77
|
+
config: options.config
|
|
78
|
+
}, {
|
|
79
|
+
projectPath,
|
|
80
|
+
fileSystem
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const shouldHealthCheck = options.healthCheck !== false;
|
|
84
|
+
if (shouldHealthCheck) {
|
|
85
|
+
health = await inspectSemanticSharedSource({
|
|
86
|
+
sourceName: registration.source.name,
|
|
87
|
+
requiredReleaseState: registration.source.required_release_state,
|
|
88
|
+
config: options.config
|
|
89
|
+
}, {
|
|
90
|
+
projectPath,
|
|
91
|
+
fileSystem
|
|
92
|
+
});
|
|
93
|
+
if (!health.success) {
|
|
94
|
+
blocked.push({
|
|
95
|
+
reason: 'health-check-failed',
|
|
96
|
+
source_name: registration.source.name
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const shouldSyncNow = options.syncNow !== false;
|
|
102
|
+
if (blocked.length === 0 && shouldSyncNow) {
|
|
103
|
+
sync = await syncSemanticSharedBundle({
|
|
104
|
+
sourceName: registration.source.name,
|
|
105
|
+
requiredReleaseState: registration.source.required_release_state,
|
|
106
|
+
config: options.config,
|
|
107
|
+
spec: specId || normalizeString(descriptor.spec_id)
|
|
108
|
+
}, {
|
|
109
|
+
projectPath,
|
|
110
|
+
fileSystem
|
|
111
|
+
});
|
|
112
|
+
if (!sync.success) {
|
|
113
|
+
blocked.push({
|
|
114
|
+
reason: 'sync-failed',
|
|
115
|
+
source_name: registration.source.name
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
api_version: SEMANTIC_SHARED_SOURCE_CONNECT_API_VERSION,
|
|
123
|
+
mode: 'semantic-connect-shared-source',
|
|
124
|
+
success: blocked.length === 0,
|
|
125
|
+
descriptor_file: descriptorPayload.descriptor_file,
|
|
126
|
+
descriptor_release_state: descriptorReleaseState,
|
|
127
|
+
source_name: registration && registration.source ? registration.source.name : normalizeString(descriptor.source && descriptor.source.name) || null,
|
|
128
|
+
config_file: registration ? registration.config_file : null,
|
|
129
|
+
registration,
|
|
130
|
+
health,
|
|
131
|
+
sync,
|
|
132
|
+
blocked
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = {
|
|
137
|
+
SEMANTIC_SHARED_SOURCE_CONNECT_API_VERSION,
|
|
138
|
+
connectSemanticSharedSource
|
|
139
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
|
|
4
|
+
const SEMANTIC_SHARED_SOURCE_DISCOVERY_API_VERSION = 'sce.semantic.shared-source-discovery/v0.1';
|
|
5
|
+
|
|
6
|
+
function normalizeString(value) {
|
|
7
|
+
if (typeof value !== 'string') {
|
|
8
|
+
return '';
|
|
9
|
+
}
|
|
10
|
+
return value.trim();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function toProjectRelative(projectPath, targetPath) {
|
|
14
|
+
return path.relative(projectPath, targetPath).replace(/\\/g, '/');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function listDescriptorFiles(projectPath, fileSystem = fs) {
|
|
18
|
+
const specsRoot = path.join(projectPath, '.sce', 'specs');
|
|
19
|
+
if (!await fileSystem.pathExists(specsRoot)) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
const specEntries = await fileSystem.readdir(specsRoot);
|
|
23
|
+
const descriptorFiles = [];
|
|
24
|
+
for (const specEntry of specEntries) {
|
|
25
|
+
const candidate = path.join(specsRoot, specEntry, 'registry', 'semantic-shared', 'published', 'source-descriptor.json');
|
|
26
|
+
if (await fileSystem.pathExists(candidate)) {
|
|
27
|
+
descriptorFiles.push(candidate);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return descriptorFiles;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function buildDiscoveryItem(projectPath, absolutePath, payload = {}) {
|
|
34
|
+
const source = payload && typeof payload.source === 'object' ? payload.source : {};
|
|
35
|
+
const publication = payload && typeof payload.publication === 'object' ? payload.publication : {};
|
|
36
|
+
const releaseState = normalizeString(publication.release_state)
|
|
37
|
+
|| normalizeString(source.required_release_state)
|
|
38
|
+
|| null;
|
|
39
|
+
const descriptorFile = toProjectRelative(projectPath, absolutePath);
|
|
40
|
+
return {
|
|
41
|
+
descriptor_file: descriptorFile,
|
|
42
|
+
spec_id: normalizeString(payload.spec_id) || null,
|
|
43
|
+
source_name: normalizeString(source.name) || 'semantic-shared',
|
|
44
|
+
bundle: normalizeString(source.bundle) || null,
|
|
45
|
+
root: normalizeString(source.root) || null,
|
|
46
|
+
required_release_state: normalizeString(source.required_release_state) || null,
|
|
47
|
+
publication_release_state: releaseState,
|
|
48
|
+
approved: releaseState === 'approved-central',
|
|
49
|
+
suggested_connect_command: `sce semantic connect-shared-source --input-file ${descriptorFile} --json`
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function discoverSemanticSharedSourceDescriptors(projectPath, dependencies = {}) {
|
|
54
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
55
|
+
const descriptorFiles = await listDescriptorFiles(projectPath, fileSystem);
|
|
56
|
+
const items = [];
|
|
57
|
+
const blocked = [];
|
|
58
|
+
|
|
59
|
+
for (const absolutePath of descriptorFiles) {
|
|
60
|
+
try {
|
|
61
|
+
const payload = await fileSystem.readJson(absolutePath);
|
|
62
|
+
if (!payload || typeof payload !== 'object' || !payload.source || typeof payload.source !== 'object') {
|
|
63
|
+
blocked.push({
|
|
64
|
+
descriptor_file: toProjectRelative(projectPath, absolutePath),
|
|
65
|
+
reason: 'invalid-descriptor-payload'
|
|
66
|
+
});
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
items.push(buildDiscoveryItem(projectPath, absolutePath, payload));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
blocked.push({
|
|
72
|
+
descriptor_file: toProjectRelative(projectPath, absolutePath),
|
|
73
|
+
reason: 'failed-to-read-descriptor',
|
|
74
|
+
detail: error.message
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
items.sort((left, right) => left.descriptor_file.localeCompare(right.descriptor_file));
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
api_version: SEMANTIC_SHARED_SOURCE_DISCOVERY_API_VERSION,
|
|
83
|
+
mode: 'semantic-shared-source-discovery',
|
|
84
|
+
project_path: projectPath,
|
|
85
|
+
summary: {
|
|
86
|
+
total: items.length,
|
|
87
|
+
approved: items.filter((item) => item.approved).length,
|
|
88
|
+
blocked: blocked.length
|
|
89
|
+
},
|
|
90
|
+
items,
|
|
91
|
+
blocked
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = {
|
|
96
|
+
SEMANTIC_SHARED_SOURCE_DISCOVERY_API_VERSION,
|
|
97
|
+
discoverSemanticSharedSourceDescriptors
|
|
98
|
+
};
|