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.
Files changed (121) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +17 -6
  3. package/README.zh.md +18 -6
  4. package/bin/scene-capability-engine.js +4 -0
  5. package/docs/README.md +2 -2
  6. package/docs/command-reference.md +382 -6
  7. package/docs/document-governance.md +3 -2
  8. package/docs/integration-modes.md +62 -478
  9. package/docs/integration-philosophy.md +56 -263
  10. package/docs/magicball-project-portfolio-contract.md +114 -2
  11. package/docs/project-management/README.md +14 -0
  12. package/docs/project-management/assurance/backup.md +3 -0
  13. package/docs/project-management/assurance/config.md +3 -0
  14. package/docs/project-management/assurance/evidence/README.md +3 -0
  15. package/docs/project-management/assurance/incidents/README.md +3 -0
  16. package/docs/project-management/assurance/logs.md +3 -0
  17. package/docs/project-management/assurance/overview.md +3 -0
  18. package/docs/project-management/assurance/recovery/README.md +3 -0
  19. package/docs/project-management/assurance/resource.md +3 -0
  20. package/docs/project-management/assurance/runbooks/README.md +3 -0
  21. package/docs/project-management/delivery/acceptance/README.md +3 -0
  22. package/docs/project-management/delivery/acceptance/evidence/README.md +3 -0
  23. package/docs/project-management/delivery/acceptance/exceptions/README.md +3 -0
  24. package/docs/project-management/delivery/acceptance/reports/README.md +3 -0
  25. package/docs/project-management/delivery/documents/changes.md +3 -0
  26. package/docs/project-management/delivery/documents/issues.md +3 -0
  27. package/docs/project-management/delivery/documents/overview.md +3 -0
  28. package/docs/project-management/delivery/documents/planning.md +3 -0
  29. package/docs/project-management/delivery/documents/requirements.md +3 -0
  30. package/docs/project-management/delivery/documents/tracking.md +3 -0
  31. package/docs/project-management/delivery/handoffs/README.md +3 -0
  32. package/docs/project-management/delivery/handoffs/evidence/README.md +3 -0
  33. package/docs/project-management/delivery/handoffs/records/README.md +3 -0
  34. package/docs/project-management/delivery/overview.md +10 -0
  35. package/docs/project-management/delivery/releases/README.md +3 -0
  36. package/docs/project-management/delivery/releases/baselines/README.md +3 -0
  37. package/docs/project-management/delivery/releases/evidence/README.md +3 -0
  38. package/docs/project-management/delivery/tables/changes.md +3 -0
  39. package/docs/project-management/delivery/tables/issues.md +3 -0
  40. package/docs/project-management/delivery/tables/planning.md +3 -0
  41. package/docs/project-management/delivery/tables/requirements.md +3 -0
  42. package/docs/project-management/delivery/tables/tracking.md +3 -0
  43. package/docs/project-management/environment/agent-discovery.md +3 -0
  44. package/docs/project-management/environment/development.md +3 -0
  45. package/docs/project-management/environment/overview.md +10 -0
  46. package/docs/project-management/environment/testing.md +3 -0
  47. package/docs/project-management/environment/version-alignment.md +3 -0
  48. package/docs/quick-start-with-ai-tools.md +68 -308
  49. package/docs/releases/README.md +2 -0
  50. package/docs/releases/v3.6.66.md +23 -0
  51. package/docs/releases/v3.6.67.md +23 -0
  52. package/docs/steering-governance.md +64 -2
  53. package/docs/zh/README.md +2 -2
  54. package/docs/zh/releases/README.md +2 -0
  55. package/docs/zh/releases/v3.6.66.md +23 -0
  56. package/docs/zh/releases/v3.6.67.md +23 -0
  57. package/lib/commands/adopt.js +24 -0
  58. package/lib/commands/native.js +158 -0
  59. package/lib/commands/project.js +95 -0
  60. package/lib/commands/semantic.js +1459 -0
  61. package/lib/commands/session.js +74 -3
  62. package/lib/commands/spec-bootstrap.js +10 -1
  63. package/lib/commands/spec-gate.js +10 -1
  64. package/lib/commands/spec-pipeline.js +10 -1
  65. package/lib/commands/studio.js +405 -30
  66. package/lib/commands/task.js +141 -7
  67. package/lib/governance/supreme-principles.js +530 -0
  68. package/lib/problem/problem-evaluator.js +4 -0
  69. package/lib/project/candidate-inspection-service.js +24 -1
  70. package/lib/project/portfolio-projection-service.js +315 -5
  71. package/lib/project/project-channel-output.js +94 -0
  72. package/lib/project/project-channel-projection.js +181 -0
  73. package/lib/project/root-onboarding-service.js +60 -8
  74. package/lib/project/semantic-shared-source-projection.js +150 -0
  75. package/lib/project/supervision-action-model.js +277 -0
  76. package/lib/project/supervision-projection-service.js +305 -5
  77. package/lib/project/target-resolution-service.js +70 -5
  78. package/lib/project/visibility-policy.js +93 -0
  79. package/lib/runtime/multi-spec-scene-session.js +8 -1
  80. package/lib/runtime/project-channel-context-store.js +387 -0
  81. package/lib/runtime/project-channel-context.js +406 -0
  82. package/lib/runtime/scene-session-binding.js +46 -0
  83. package/lib/runtime/session-store.js +186 -0
  84. package/lib/runtime/steering-contract.js +7 -1
  85. package/lib/semantic/archive-report.js +283 -0
  86. package/lib/semantic/archive-routing.js +67 -0
  87. package/lib/semantic/backflow-report.js +245 -0
  88. package/lib/semantic/capability-contract.js +30 -0
  89. package/lib/semantic/delta-export.js +145 -0
  90. package/lib/semantic/interaction-observer.js +254 -0
  91. package/lib/semantic/kernel-loader.js +881 -0
  92. package/lib/semantic/native-runtime.js +359 -0
  93. package/lib/semantic/progress-ledger.js +433 -0
  94. package/lib/semantic/replay-evaluator.js +382 -0
  95. package/lib/semantic/shared-publication.js +592 -0
  96. package/lib/semantic/shared-source-config.js +183 -0
  97. package/lib/semantic/shared-source-connect.js +139 -0
  98. package/lib/semantic/shared-source-discovery.js +98 -0
  99. package/lib/semantic/shared-sync-export.js +413 -0
  100. package/lib/semantic/shared-sync-intake.js +592 -0
  101. package/lib/semantic/shared-sync-merge.js +547 -0
  102. package/lib/semantic/shared-sync-release.js +463 -0
  103. package/lib/semantic/supreme-intent-report.js +300 -0
  104. package/lib/state/sce-state-store.js +1360 -0
  105. package/lib/steering/context-sync-manager.js +276 -25
  106. package/lib/studio/spec-intake-governor.js +39 -3
  107. package/lib/studio/task-envelope.js +35 -2
  108. package/lib/workspace/takeover-baseline.js +342 -83
  109. package/package.json +7 -2
  110. package/scripts/agent-governance-baseline-audit.js +395 -0
  111. package/scripts/clarification-first-audit.js +9 -9
  112. package/scripts/deprecated-entry-audit.js +240 -0
  113. package/scripts/release-posture-report.js +262 -0
  114. package/template/.sce/README.md +62 -228
  115. package/template/.sce/config/semantic-shared-sources.json +5 -0
  116. package/template/.sce/config/supreme-principles-policy.json +105 -0
  117. package/template/.sce/config/takeover-baseline.json +7 -0
  118. package/template/.sce/steering/CORE_PRINCIPLES.md +23 -63
  119. package/template/.sce/steering/CURRENT_CONTEXT.md +4 -0
  120. package/template/.sce/steering/RULES_GUIDE.md +17 -9
  121. 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
+ };