scene-capability-engine 3.6.64 → 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 +26 -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 +385 -8
- package/docs/document-governance.md +3 -2
- package/docs/integration-modes.md +62 -478
- package/docs/integration-philosophy.md +56 -263
- package/docs/magicball-cli-invocation-examples.md +1 -0
- package/docs/magicball-project-portfolio-contract.md +125 -4
- 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 +3 -0
- package/docs/releases/v3.6.65.md +25 -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 +3 -0
- package/docs/zh/releases/v3.6.65.md +25 -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 +96 -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 +107 -7
- 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-doc-version-audit.js +24 -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
|
@@ -4,6 +4,22 @@ const fs = require('fs-extra');
|
|
|
4
4
|
const WorkspaceStateManager = require('../workspace/multi/workspace-state-manager');
|
|
5
5
|
const { SessionStore } = require('../runtime/session-store');
|
|
6
6
|
const { getCurrentDeviceProfile } = require('../device/current-device');
|
|
7
|
+
const {
|
|
8
|
+
buildEmptySummary,
|
|
9
|
+
buildSemanticSharedSourceProjection
|
|
10
|
+
} = require('./semantic-shared-source-projection');
|
|
11
|
+
const {
|
|
12
|
+
buildEmptyProjectChannelProjection,
|
|
13
|
+
buildProjectChannelProjection
|
|
14
|
+
} = require('./project-channel-projection');
|
|
15
|
+
const { buildSupervisionActionQueue } = require('./supervision-action-model');
|
|
16
|
+
const { buildSupremeIntentGovernanceReport } = require('../semantic/supreme-intent-report');
|
|
17
|
+
const { buildSemanticBackflowReport } = require('../semantic/backflow-report');
|
|
18
|
+
const { buildSemanticArchiveReport } = require('../semantic/archive-report');
|
|
19
|
+
const {
|
|
20
|
+
classifyProjectVisibility,
|
|
21
|
+
isCallerVisibleProject
|
|
22
|
+
} = require('./visibility-policy');
|
|
7
23
|
|
|
8
24
|
function normalizeString(value) {
|
|
9
25
|
if (typeof value !== 'string') {
|
|
@@ -130,6 +146,176 @@ function deriveStatus({ accessible, isCurrentProject, activeSessionCount }) {
|
|
|
130
146
|
return 'idle';
|
|
131
147
|
}
|
|
132
148
|
|
|
149
|
+
function buildProjectSupervisionSignalCandidates(projectId, reports = {}) {
|
|
150
|
+
const archiveTotals = reports.archiveReport && reports.archiveReport.totals && typeof reports.archiveReport.totals === 'object'
|
|
151
|
+
? reports.archiveReport.totals
|
|
152
|
+
: {};
|
|
153
|
+
const backflowTotals = reports.backflowReport && reports.backflowReport.totals && typeof reports.backflowReport.totals === 'object'
|
|
154
|
+
? reports.backflowReport.totals
|
|
155
|
+
: {};
|
|
156
|
+
const governanceHotspots = Array.isArray(reports.governanceReport && reports.governanceReport.top_scope_hotspots)
|
|
157
|
+
? reports.governanceReport.top_scope_hotspots
|
|
158
|
+
: [];
|
|
159
|
+
const libraryRecords = Array.isArray(reports.archiveReport && reports.archiveReport.by_library)
|
|
160
|
+
? reports.archiveReport.by_library
|
|
161
|
+
: [];
|
|
162
|
+
const pendingConnectCount = Number(reports.semanticSharedSources && reports.semanticSharedSources.pendingApprovedDescriptors || 0);
|
|
163
|
+
const items = [];
|
|
164
|
+
|
|
165
|
+
if (Number(archiveTotals.missing_archive_count || 0) > 0) {
|
|
166
|
+
items.push({
|
|
167
|
+
id: `portfolio:archive-missing:${projectId}`,
|
|
168
|
+
kind: 'archive',
|
|
169
|
+
state: 'archive-routing-missing',
|
|
170
|
+
missingArchiveCount: Number(archiveTotals.missing_archive_count || 0),
|
|
171
|
+
updatedAt: reports.generatedAt
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (Number(backflowTotals.central_release_blocked || 0) > 0) {
|
|
176
|
+
items.push({
|
|
177
|
+
id: `portfolio:central-release:${projectId}`,
|
|
178
|
+
kind: 'backflow',
|
|
179
|
+
state: 'central-release-blocked',
|
|
180
|
+
specId: Array.isArray(reports.backflowReport && reports.backflowReport.blocked_spec_ids)
|
|
181
|
+
? normalizeString(reports.backflowReport.blocked_spec_ids[0])
|
|
182
|
+
: '',
|
|
183
|
+
blockedCount: Number(backflowTotals.central_release_blocked || 0),
|
|
184
|
+
updatedAt: reports.generatedAt
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (Number(backflowTotals.central_merge_blocked || 0) > 0) {
|
|
189
|
+
items.push({
|
|
190
|
+
id: `portfolio:central-merge:${projectId}`,
|
|
191
|
+
kind: 'backflow',
|
|
192
|
+
state: 'central-merge-blocked',
|
|
193
|
+
specId: Array.isArray(reports.backflowReport && reports.backflowReport.blocked_spec_ids)
|
|
194
|
+
? normalizeString(reports.backflowReport.blocked_spec_ids[0])
|
|
195
|
+
: '',
|
|
196
|
+
blockedCount: Number(backflowTotals.central_merge_blocked || 0),
|
|
197
|
+
updatedAt: reports.generatedAt
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (Number(backflowTotals.local_publish_blocked || 0) > 0) {
|
|
202
|
+
items.push({
|
|
203
|
+
id: `portfolio:local-backflow:${projectId}`,
|
|
204
|
+
kind: 'backflow',
|
|
205
|
+
state: 'local-publish-blocked',
|
|
206
|
+
specId: Array.isArray(reports.backflowReport && reports.backflowReport.blocked_spec_ids)
|
|
207
|
+
? normalizeString(reports.backflowReport.blocked_spec_ids[0])
|
|
208
|
+
: '',
|
|
209
|
+
blockedCount: Number(backflowTotals.local_publish_blocked || 0),
|
|
210
|
+
updatedAt: reports.generatedAt
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const topGovernanceHotspot = governanceHotspots.find((item) => Number(item && item.governed_count || 0) > 0);
|
|
215
|
+
if (topGovernanceHotspot) {
|
|
216
|
+
items.push({
|
|
217
|
+
id: `portfolio:governance:${projectId}:${normalizeString(topGovernanceHotspot.channel_id) || 'channel'}`,
|
|
218
|
+
kind: 'governance',
|
|
219
|
+
state: Number(topGovernanceHotspot.refuse || 0) > 0 ? 'refuse-hotspot' : 'rewrite-hotspot',
|
|
220
|
+
channelId: normalizeString(topGovernanceHotspot.channel_id),
|
|
221
|
+
sceneId: normalizeString(topGovernanceHotspot.scene_id),
|
|
222
|
+
specId: normalizeString(topGovernanceHotspot.spec_id),
|
|
223
|
+
governedCount: Number(topGovernanceHotspot.governed_count || 0),
|
|
224
|
+
updatedAt: safeIsoAt(topGovernanceHotspot.latest_at) || reports.generatedAt
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (pendingConnectCount > 0) {
|
|
229
|
+
items.push({
|
|
230
|
+
id: `portfolio:shared-source:${projectId}`,
|
|
231
|
+
kind: 'info',
|
|
232
|
+
state: 'pending-connect',
|
|
233
|
+
descriptorFile: '.sce/specs/<spec>/registry/semantic-shared/published/source-descriptor.json',
|
|
234
|
+
updatedAt: reports.generatedAt
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const archivePressure = libraryRecords.find((item) => (
|
|
239
|
+
Number(item && item.publish_blocked_count || 0) > 0
|
|
240
|
+
|| Number(item && item.publish_pending_count || 0) > 0
|
|
241
|
+
|| Number(item && item.lesson_count || 0) > 0
|
|
242
|
+
|| Number(item && item.ledger_count || 0) > 0
|
|
243
|
+
));
|
|
244
|
+
if (archivePressure) {
|
|
245
|
+
items.push({
|
|
246
|
+
id: `portfolio:archive:${projectId}:${normalizeString(archivePressure.target_library) || 'library'}`,
|
|
247
|
+
kind: 'archive',
|
|
248
|
+
state: Number(archivePressure.published_shared_count || 0) > 0 ? 'shared-accumulating' : 'local-accumulating',
|
|
249
|
+
targetLibrary: normalizeString(archivePressure.target_library),
|
|
250
|
+
publishPendingCount: Number(archivePressure.publish_pending_count || 0),
|
|
251
|
+
publishBlockedCount: Number(archivePressure.publish_blocked_count || 0),
|
|
252
|
+
updatedAt: reports.generatedAt
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return items;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async function buildProjectSupervisionSignals(projectId, projectRoot, semanticSharedSources, dependencies = {}) {
|
|
260
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
261
|
+
const archiveReport = await buildSemanticArchiveReport({
|
|
262
|
+
project_id: projectId,
|
|
263
|
+
limit: 50,
|
|
264
|
+
recent_limit: 5
|
|
265
|
+
}, {
|
|
266
|
+
...dependencies,
|
|
267
|
+
projectPath: projectRoot,
|
|
268
|
+
fileSystem
|
|
269
|
+
});
|
|
270
|
+
const backflowReport = await buildSemanticBackflowReport({
|
|
271
|
+
project_id: projectId,
|
|
272
|
+
limit: 50,
|
|
273
|
+
recent_limit: 5
|
|
274
|
+
}, {
|
|
275
|
+
...dependencies,
|
|
276
|
+
projectPath: projectRoot,
|
|
277
|
+
fileSystem
|
|
278
|
+
});
|
|
279
|
+
const governanceReport = await buildSupremeIntentGovernanceReport({
|
|
280
|
+
project_id: projectId,
|
|
281
|
+
limit: 50,
|
|
282
|
+
hotspot_limit: 3,
|
|
283
|
+
recent_limit: 3
|
|
284
|
+
}, {
|
|
285
|
+
...dependencies,
|
|
286
|
+
projectPath: projectRoot,
|
|
287
|
+
fileSystem
|
|
288
|
+
});
|
|
289
|
+
const generatedAt = new Date().toISOString();
|
|
290
|
+
const candidates = buildProjectSupervisionSignalCandidates(projectId, {
|
|
291
|
+
generatedAt,
|
|
292
|
+
archiveReport,
|
|
293
|
+
backflowReport,
|
|
294
|
+
governanceReport,
|
|
295
|
+
semanticSharedSources
|
|
296
|
+
});
|
|
297
|
+
const actionProjection = buildSupervisionActionQueue(candidates, { projectId });
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
highestSeverity: actionProjection.summary.highestSeverity,
|
|
301
|
+
actionableCount: actionProjection.summary.actionableCount,
|
|
302
|
+
archiveMissingCount: Number(archiveReport.totals.missing_archive_count || 0),
|
|
303
|
+
backflowBlockedCount: Number(backflowReport.totals.local_publish_blocked || 0)
|
|
304
|
+
+ Number(backflowReport.totals.central_merge_blocked || 0)
|
|
305
|
+
+ Number(backflowReport.totals.central_release_blocked || 0),
|
|
306
|
+
governanceHotspotCount: governanceHotspotsCount(governanceReport),
|
|
307
|
+
pendingConnectCount: Number(semanticSharedSources.pendingApprovedDescriptors || 0),
|
|
308
|
+
...(actionProjection.summary.actionableCount > 0
|
|
309
|
+
? { primaryRecommendedCommand: `sce project supervision show --project ${projectId} --json` }
|
|
310
|
+
: {})
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function governanceHotspotsCount(report = {}) {
|
|
315
|
+
const hotspots = Array.isArray(report.top_scope_hotspots) ? report.top_scope_hotspots : [];
|
|
316
|
+
return hotspots.filter((item) => Number(item && item.governed_count || 0) > 0).length;
|
|
317
|
+
}
|
|
318
|
+
|
|
133
319
|
async function readSceneRecords(projectRoot, dependencies = {}) {
|
|
134
320
|
const fileSystem = dependencies.fileSystem || fs;
|
|
135
321
|
const env = dependencies.env || process.env;
|
|
@@ -152,6 +338,16 @@ async function buildRegisteredWorkspaceRecord(workspace, context = {}, dependenc
|
|
|
152
338
|
let partial = false;
|
|
153
339
|
let sceneRecords = [];
|
|
154
340
|
let specCount = 0;
|
|
341
|
+
let semanticSharedSources = buildEmptySummary();
|
|
342
|
+
let projectChannelContext = buildEmptyProjectChannelProjection().summary;
|
|
343
|
+
let supervisionSignals = {
|
|
344
|
+
highestSeverity: 'none',
|
|
345
|
+
actionableCount: 0,
|
|
346
|
+
archiveMissingCount: 0,
|
|
347
|
+
backflowBlockedCount: 0,
|
|
348
|
+
governanceHotspotCount: 0,
|
|
349
|
+
pendingConnectCount: 0
|
|
350
|
+
};
|
|
155
351
|
|
|
156
352
|
const sceProject = await isValidSceProjectRoot(projectRoot, fileSystem);
|
|
157
353
|
if (!sceProject) {
|
|
@@ -171,6 +367,35 @@ async function buildRegisteredWorkspaceRecord(workspace, context = {}, dependenc
|
|
|
171
367
|
partial = true;
|
|
172
368
|
partialReasons.push('spec_inventory_unavailable');
|
|
173
369
|
}
|
|
370
|
+
const semanticSharedSourceProjection = await buildSemanticSharedSourceProjection(projectRoot, {
|
|
371
|
+
fileSystem
|
|
372
|
+
});
|
|
373
|
+
semanticSharedSources = semanticSharedSourceProjection.summary;
|
|
374
|
+
if (semanticSharedSourceProjection.partial) {
|
|
375
|
+
partial = true;
|
|
376
|
+
partialReasons.push(...semanticSharedSourceProjection.partialReasons);
|
|
377
|
+
}
|
|
378
|
+
const projectChannelProjection = await buildProjectChannelProjection(projectRoot, {
|
|
379
|
+
preferredProjectIds: [projectId, workspaceId]
|
|
380
|
+
}, {
|
|
381
|
+
fileSystem
|
|
382
|
+
});
|
|
383
|
+
projectChannelContext = projectChannelProjection.summary;
|
|
384
|
+
if (projectChannelProjection.partial) {
|
|
385
|
+
partial = true;
|
|
386
|
+
partialReasons.push(...projectChannelProjection.partialReasons);
|
|
387
|
+
}
|
|
388
|
+
try {
|
|
389
|
+
supervisionSignals = await buildProjectSupervisionSignals(
|
|
390
|
+
projectId,
|
|
391
|
+
projectRoot,
|
|
392
|
+
semanticSharedSources,
|
|
393
|
+
dependencies
|
|
394
|
+
);
|
|
395
|
+
} catch (_error) {
|
|
396
|
+
partial = true;
|
|
397
|
+
partialReasons.push('supervision_signals_unavailable');
|
|
398
|
+
}
|
|
174
399
|
}
|
|
175
400
|
|
|
176
401
|
const sceneCount = Array.isArray(sceneRecords) ? sceneRecords.length : 0;
|
|
@@ -180,12 +405,19 @@ async function buildRegisteredWorkspaceRecord(workspace, context = {}, dependenc
|
|
|
180
405
|
const lastActivityAt = collectRecordActivityTimestamps(sceneRecords);
|
|
181
406
|
const uniquePartialReasons = Array.from(new Set(partialReasons));
|
|
182
407
|
const isCurrentProject = context.projectId === projectId;
|
|
408
|
+
const visibilityInfo = classifyProjectVisibility({
|
|
409
|
+
workspaceId,
|
|
410
|
+
projectRoot,
|
|
411
|
+
projectName: path.basename(projectRoot) || workspaceId
|
|
412
|
+
});
|
|
183
413
|
|
|
184
414
|
return {
|
|
185
415
|
projectId,
|
|
186
416
|
workspaceId,
|
|
187
417
|
projectRoot,
|
|
188
418
|
projectName: path.basename(projectRoot) || workspaceId,
|
|
419
|
+
visibility: visibilityInfo.visibility,
|
|
420
|
+
lifecycle: visibilityInfo.lifecycle,
|
|
189
421
|
provenance: 'registered',
|
|
190
422
|
readiness: deriveReadiness({
|
|
191
423
|
accessible,
|
|
@@ -208,6 +440,9 @@ async function buildRegisteredWorkspaceRecord(workspace, context = {}, dependenc
|
|
|
208
440
|
sceneCount,
|
|
209
441
|
specCount
|
|
210
442
|
},
|
|
443
|
+
semanticSharedSources,
|
|
444
|
+
supervisionSignals,
|
|
445
|
+
projectChannelContext,
|
|
211
446
|
partial,
|
|
212
447
|
partialReasons: uniquePartialReasons
|
|
213
448
|
};
|
|
@@ -221,6 +456,16 @@ async function buildLocalProjectRecord(projectRoot, context = {}, dependencies =
|
|
|
221
456
|
let specCount = 0;
|
|
222
457
|
const partialReasons = ['unregistered_project'];
|
|
223
458
|
let partial = true;
|
|
459
|
+
let semanticSharedSources = buildEmptySummary();
|
|
460
|
+
let projectChannelContext = buildEmptyProjectChannelProjection().summary;
|
|
461
|
+
let supervisionSignals = {
|
|
462
|
+
highestSeverity: 'none',
|
|
463
|
+
actionableCount: 0,
|
|
464
|
+
archiveMissingCount: 0,
|
|
465
|
+
backflowBlockedCount: 0,
|
|
466
|
+
governanceHotspotCount: 0,
|
|
467
|
+
pendingConnectCount: 0
|
|
468
|
+
};
|
|
224
469
|
|
|
225
470
|
try {
|
|
226
471
|
sceneRecords = await readSceneRecords(normalizedRoot, dependencies);
|
|
@@ -232,6 +477,32 @@ async function buildLocalProjectRecord(projectRoot, context = {}, dependencies =
|
|
|
232
477
|
} catch (_error) {
|
|
233
478
|
partialReasons.push('spec_inventory_unavailable');
|
|
234
479
|
}
|
|
480
|
+
const semanticSharedSourceProjection = await buildSemanticSharedSourceProjection(normalizedRoot, {
|
|
481
|
+
fileSystem
|
|
482
|
+
});
|
|
483
|
+
semanticSharedSources = semanticSharedSourceProjection.summary;
|
|
484
|
+
if (semanticSharedSourceProjection.partial) {
|
|
485
|
+
partialReasons.push(...semanticSharedSourceProjection.partialReasons);
|
|
486
|
+
}
|
|
487
|
+
const projectChannelProjection = await buildProjectChannelProjection(normalizedRoot, {
|
|
488
|
+
preferredProjectIds: [projectId, path.basename(normalizedRoot)]
|
|
489
|
+
}, {
|
|
490
|
+
fileSystem
|
|
491
|
+
});
|
|
492
|
+
projectChannelContext = projectChannelProjection.summary;
|
|
493
|
+
if (projectChannelProjection.partial) {
|
|
494
|
+
partialReasons.push(...projectChannelProjection.partialReasons);
|
|
495
|
+
}
|
|
496
|
+
try {
|
|
497
|
+
supervisionSignals = await buildProjectSupervisionSignals(
|
|
498
|
+
projectId,
|
|
499
|
+
normalizedRoot,
|
|
500
|
+
semanticSharedSources,
|
|
501
|
+
dependencies
|
|
502
|
+
);
|
|
503
|
+
} catch (_error) {
|
|
504
|
+
partialReasons.push('supervision_signals_unavailable');
|
|
505
|
+
}
|
|
235
506
|
|
|
236
507
|
const sceneCount = Array.isArray(sceneRecords) ? sceneRecords.length : 0;
|
|
237
508
|
const activeSessionCount = Array.isArray(sceneRecords)
|
|
@@ -240,11 +511,17 @@ async function buildLocalProjectRecord(projectRoot, context = {}, dependencies =
|
|
|
240
511
|
const lastActivityAt = collectRecordActivityTimestamps(sceneRecords);
|
|
241
512
|
const uniquePartialReasons = Array.from(new Set(partialReasons));
|
|
242
513
|
const isCurrentProject = context.projectId === projectId;
|
|
514
|
+
const visibilityInfo = classifyProjectVisibility({
|
|
515
|
+
projectRoot: normalizedRoot,
|
|
516
|
+
projectName: path.basename(normalizedRoot) || 'local-project'
|
|
517
|
+
});
|
|
243
518
|
|
|
244
519
|
return {
|
|
245
520
|
projectId,
|
|
246
521
|
projectRoot: normalizedRoot,
|
|
247
522
|
projectName: path.basename(normalizedRoot) || 'local-project',
|
|
523
|
+
visibility: visibilityInfo.visibility,
|
|
524
|
+
lifecycle: visibilityInfo.lifecycle,
|
|
248
525
|
provenance: 'discovered',
|
|
249
526
|
readiness: deriveReadiness({
|
|
250
527
|
accessible: true,
|
|
@@ -267,6 +544,9 @@ async function buildLocalProjectRecord(projectRoot, context = {}, dependencies =
|
|
|
267
544
|
sceneCount,
|
|
268
545
|
specCount
|
|
269
546
|
},
|
|
547
|
+
semanticSharedSources,
|
|
548
|
+
supervisionSignals,
|
|
549
|
+
projectChannelContext,
|
|
270
550
|
partial,
|
|
271
551
|
partialReasons: uniquePartialReasons
|
|
272
552
|
};
|
|
@@ -282,6 +562,12 @@ async function resolveCurrentProjectContext(options = {}, dependencies = {}) {
|
|
|
282
562
|
if (!workspace) {
|
|
283
563
|
throw new Error(`workspace not found: ${explicitWorkspace}`);
|
|
284
564
|
}
|
|
565
|
+
if (!isCallerVisibleProject({
|
|
566
|
+
workspaceId: workspace.name,
|
|
567
|
+
projectRoot: normalizePath(workspace.path)
|
|
568
|
+
})) {
|
|
569
|
+
throw new Error(`workspace not visible: ${explicitWorkspace}`);
|
|
570
|
+
}
|
|
285
571
|
return {
|
|
286
572
|
workspaceId: workspace.name,
|
|
287
573
|
projectId: buildWorkspaceProjectId(workspace.name),
|
|
@@ -291,7 +577,10 @@ async function resolveCurrentProjectContext(options = {}, dependencies = {}) {
|
|
|
291
577
|
}
|
|
292
578
|
|
|
293
579
|
const matchedWorkspace = await stateManager.findWorkspaceByPath(currentDir);
|
|
294
|
-
if (matchedWorkspace
|
|
580
|
+
if (matchedWorkspace && isCallerVisibleProject({
|
|
581
|
+
workspaceId: matchedWorkspace.name,
|
|
582
|
+
projectRoot: normalizePath(matchedWorkspace.path)
|
|
583
|
+
})) {
|
|
295
584
|
return {
|
|
296
585
|
workspaceId: matchedWorkspace.name,
|
|
297
586
|
projectId: buildWorkspaceProjectId(matchedWorkspace.name),
|
|
@@ -301,7 +590,10 @@ async function resolveCurrentProjectContext(options = {}, dependencies = {}) {
|
|
|
301
590
|
}
|
|
302
591
|
|
|
303
592
|
const activeWorkspace = await stateManager.getActiveWorkspace();
|
|
304
|
-
if (activeWorkspace
|
|
593
|
+
if (activeWorkspace && isCallerVisibleProject({
|
|
594
|
+
workspaceId: activeWorkspace.name,
|
|
595
|
+
projectRoot: normalizePath(activeWorkspace.path)
|
|
596
|
+
})) {
|
|
305
597
|
return {
|
|
306
598
|
workspaceId: activeWorkspace.name,
|
|
307
599
|
projectId: buildWorkspaceProjectId(activeWorkspace.name),
|
|
@@ -310,7 +602,10 @@ async function resolveCurrentProjectContext(options = {}, dependencies = {}) {
|
|
|
310
602
|
};
|
|
311
603
|
}
|
|
312
604
|
|
|
313
|
-
if (
|
|
605
|
+
if (
|
|
606
|
+
await isValidSceProjectRoot(currentDir, dependencies.fileSystem || fs)
|
|
607
|
+
&& isCallerVisibleProject({ projectRoot: currentDir })
|
|
608
|
+
) {
|
|
314
609
|
return {
|
|
315
610
|
workspaceId: null,
|
|
316
611
|
projectId: buildLocalProjectId(currentDir),
|
|
@@ -347,8 +642,20 @@ async function buildProjectPortfolioProjection(options = {}, dependencies = {})
|
|
|
347
642
|
|
|
348
643
|
const workspaces = await stateManager.listWorkspaces();
|
|
349
644
|
const records = [];
|
|
645
|
+
const hiddenWorkspaceIds = [];
|
|
350
646
|
for (const workspace of workspaces) {
|
|
351
|
-
|
|
647
|
+
const record = await buildRegisteredWorkspaceRecord(workspace, currentContext, dependencies);
|
|
648
|
+
if (record.visibility !== 'managed') {
|
|
649
|
+
if (record.lifecycle === 'ephemeral' && record.availability === 'inaccessible') {
|
|
650
|
+
hiddenWorkspaceIds.push(record.workspaceId);
|
|
651
|
+
}
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
records.push(record);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
for (const workspaceId of hiddenWorkspaceIds) {
|
|
658
|
+
await stateManager.removeWorkspace(workspaceId);
|
|
352
659
|
}
|
|
353
660
|
|
|
354
661
|
const localRoot = normalizeString(currentContext.projectRoot);
|
|
@@ -357,7 +664,10 @@ async function buildProjectPortfolioProjection(options = {}, dependencies = {})
|
|
|
357
664
|
&& localRoot
|
|
358
665
|
&& !currentDirWorkspace;
|
|
359
666
|
if (shouldAddLocalProject) {
|
|
360
|
-
|
|
667
|
+
const localRecord = await buildLocalProjectRecord(localRoot, currentContext, dependencies);
|
|
668
|
+
if (localRecord.visibility === 'managed') {
|
|
669
|
+
records.push(localRecord);
|
|
670
|
+
}
|
|
361
671
|
}
|
|
362
672
|
|
|
363
673
|
records.sort((left, right) => {
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
function normalizeString(value) {
|
|
2
|
+
if (typeof value !== 'string') {
|
|
3
|
+
return '';
|
|
4
|
+
}
|
|
5
|
+
return value.trim();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function buildProjectChannelOutput(options = {}) {
|
|
9
|
+
const context = options.context && typeof options.context === 'object'
|
|
10
|
+
? options.context
|
|
11
|
+
: null;
|
|
12
|
+
const channel = options.channel && typeof options.channel === 'object'
|
|
13
|
+
? options.channel
|
|
14
|
+
: null;
|
|
15
|
+
const session = options.session && typeof options.session === 'object'
|
|
16
|
+
? options.session
|
|
17
|
+
: null;
|
|
18
|
+
const fallback = options.fallback && typeof options.fallback === 'object'
|
|
19
|
+
? options.fallback
|
|
20
|
+
: {};
|
|
21
|
+
const requestedChannelId = normalizeString(
|
|
22
|
+
options.requestedChannelId !== undefined
|
|
23
|
+
? options.requestedChannelId
|
|
24
|
+
: fallback.requested_channel_id
|
|
25
|
+
) || null;
|
|
26
|
+
const resolvedChannelId = normalizeString(
|
|
27
|
+
options.resolvedChannelId !== undefined
|
|
28
|
+
? options.resolvedChannelId
|
|
29
|
+
: (channel && channel.channelId)
|
|
30
|
+
) || null;
|
|
31
|
+
const focusedChannelId = normalizeString(
|
|
32
|
+
options.focusedChannelId !== undefined
|
|
33
|
+
? options.focusedChannelId
|
|
34
|
+
: (context && context.focusedChannelId)
|
|
35
|
+
) || normalizeString(fallback.focused_channel_id) || null;
|
|
36
|
+
const contextAvailable = options.contextAvailable !== undefined
|
|
37
|
+
? options.contextAvailable === true
|
|
38
|
+
: context !== null;
|
|
39
|
+
const storageMode = normalizeString(
|
|
40
|
+
options.storageMode !== undefined
|
|
41
|
+
? options.storageMode
|
|
42
|
+
: fallback.storage_mode
|
|
43
|
+
) || (contextAvailable ? 'unknown' : 'none');
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
project_id: normalizeString(
|
|
47
|
+
options.projectId !== undefined
|
|
48
|
+
? options.projectId
|
|
49
|
+
: fallback.project_id
|
|
50
|
+
) || null,
|
|
51
|
+
canonical_project_id: normalizeString(
|
|
52
|
+
options.canonicalProjectId !== undefined
|
|
53
|
+
? options.canonicalProjectId
|
|
54
|
+
: fallback.canonical_project_id
|
|
55
|
+
) || null,
|
|
56
|
+
context_available: contextAvailable,
|
|
57
|
+
storage_mode: storageMode,
|
|
58
|
+
requested_channel_id: requestedChannelId,
|
|
59
|
+
focused_channel_id: focusedChannelId,
|
|
60
|
+
channel_id: resolvedChannelId || normalizeString(fallback.channel_id) || null,
|
|
61
|
+
active_scene: normalizeString(channel ? channel.activeScene : fallback.active_scene) || null,
|
|
62
|
+
active_spec_id: normalizeString(channel ? channel.activeSpecId : fallback.active_spec_id) || null,
|
|
63
|
+
active_doc: normalizeString(channel ? channel.activeDoc : fallback.active_doc) || null,
|
|
64
|
+
active_session_path: normalizeString(channel ? channel.activeSessionPath : fallback.active_session_path) || null,
|
|
65
|
+
run_state: normalizeString(channel ? channel.runState : fallback.run_state) || null,
|
|
66
|
+
updated_at: normalizeString(channel ? channel.updatedAt : fallback.updated_at) || null,
|
|
67
|
+
resolved_session_id: normalizeString(
|
|
68
|
+
options.resolvedSessionId !== undefined
|
|
69
|
+
? options.resolvedSessionId
|
|
70
|
+
: (session && session.session_id)
|
|
71
|
+
) || normalizeString(fallback.resolved_session_id) || null
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function buildProjectChannelOutputFromProjection(projection = {}, options = {}) {
|
|
76
|
+
const summary = projection && projection.summary && typeof projection.summary === 'object'
|
|
77
|
+
? projection.summary
|
|
78
|
+
: {};
|
|
79
|
+
return buildProjectChannelOutput({
|
|
80
|
+
projectId: options.projectId !== undefined ? options.projectId : summary.contextProjectId,
|
|
81
|
+
canonicalProjectId: options.canonicalProjectId,
|
|
82
|
+
requestedChannelId: options.requestedChannelId,
|
|
83
|
+
focusedChannelId: summary.focusedChannelId,
|
|
84
|
+
contextAvailable: summary.available === true,
|
|
85
|
+
storageMode: summary.storageMode,
|
|
86
|
+
channel: projection && projection.resolvedChannel ? projection.resolvedChannel : null,
|
|
87
|
+
resolvedSessionId: options.resolvedSessionId
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = {
|
|
92
|
+
buildProjectChannelOutput,
|
|
93
|
+
buildProjectChannelOutputFromProjection
|
|
94
|
+
};
|