scene-capability-engine 3.6.57 → 3.6.59

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 (36) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +5 -3
  3. package/README.zh.md +5 -3
  4. package/bin/scene-capability-engine.js +2 -0
  5. package/docs/command-reference.md +72 -0
  6. package/docs/magicball-adaptation-task-checklist-v1.md +65 -10
  7. package/docs/magicball-cli-invocation-examples.md +53 -8
  8. package/docs/magicball-engineering-projection-contract.md +175 -0
  9. package/docs/magicball-frontend-state-and-command-mapping.md +42 -5
  10. package/docs/magicball-integration-doc-index.md +19 -5
  11. package/docs/magicball-integration-issue-tracker.md +15 -5
  12. package/docs/magicball-mode-home-and-ontology-empty-state-playbook.md +13 -5
  13. package/docs/magicball-project-portfolio-contract.md +216 -0
  14. package/docs/magicball-sce-adaptation-guide.md +18 -4
  15. package/docs/magicball-ui-surface-checklist.md +25 -0
  16. package/docs/magicball-write-auth-adaptation-guide.md +3 -1
  17. package/docs/release-checklist.md +8 -0
  18. package/docs/releases/README.md +2 -0
  19. package/docs/releases/v3.6.58.md +27 -0
  20. package/docs/releases/v3.6.59.md +18 -0
  21. package/docs/zh/release-checklist.md +8 -0
  22. package/docs/zh/releases/README.md +2 -0
  23. package/docs/zh/releases/v3.6.58.md +27 -0
  24. package/docs/zh/releases/v3.6.59.md +18 -0
  25. package/lib/app/engineering-scaffold-service.js +154 -0
  26. package/lib/commands/app.js +442 -13
  27. package/lib/commands/project.js +105 -0
  28. package/lib/commands/scene.js +16 -0
  29. package/lib/project/portfolio-projection-service.js +389 -0
  30. package/lib/project/supervision-projection-service.js +329 -0
  31. package/lib/project/target-resolution-service.js +180 -0
  32. package/lib/scene/delivery-projection-service.js +650 -0
  33. package/package.json +6 -2
  34. package/scripts/magicball-engineering-contract-audit.js +347 -0
  35. package/scripts/magicball-project-contract-audit.js +254 -0
  36. package/template/.sce/README.md +2 -2
@@ -0,0 +1,180 @@
1
+ const path = require('path');
2
+ const { buildProjectPortfolioProjection } = require('./portfolio-projection-service');
3
+
4
+ function normalizeString(value) {
5
+ if (typeof value !== 'string') {
6
+ return '';
7
+ }
8
+ return value.trim();
9
+ }
10
+
11
+ function normalizeText(value) {
12
+ return normalizeString(value).toLowerCase();
13
+ }
14
+
15
+ function collectProjectAliases(project = {}) {
16
+ const aliases = [];
17
+ const fields = [
18
+ project.projectId,
19
+ project.workspaceId,
20
+ project.projectName,
21
+ project.appKey,
22
+ project.projectRoot ? path.basename(project.projectRoot) : null
23
+ ];
24
+ for (const field of fields) {
25
+ const normalized = normalizeText(field);
26
+ if (!normalized || aliases.includes(normalized)) {
27
+ continue;
28
+ }
29
+ aliases.push(normalized);
30
+ }
31
+ return aliases;
32
+ }
33
+
34
+ function scoreProjectMatch(requestText, project = {}) {
35
+ const normalizedRequest = normalizeText(requestText);
36
+ if (!normalizedRequest) {
37
+ return null;
38
+ }
39
+
40
+ const aliases = collectProjectAliases(project);
41
+ let bestScore = 0;
42
+ let reasonCode = 'target.request_match';
43
+
44
+ for (const alias of aliases) {
45
+ if (normalizedRequest === alias) {
46
+ bestScore = Math.max(bestScore, 1);
47
+ reasonCode = 'target.alias_exact_match';
48
+ continue;
49
+ }
50
+ if (normalizedRequest.includes(alias) && alias.length >= 2) {
51
+ bestScore = Math.max(bestScore, 0.96);
52
+ reasonCode = 'target.alias_contained_match';
53
+ continue;
54
+ }
55
+ if (alias.includes(normalizedRequest) && normalizedRequest.length >= 3) {
56
+ bestScore = Math.max(bestScore, 0.84);
57
+ reasonCode = 'target.alias_prefix_match';
58
+ }
59
+ }
60
+
61
+ if (bestScore <= 0) {
62
+ return null;
63
+ }
64
+
65
+ return {
66
+ projectId: project.projectId,
67
+ workspaceId: project.workspaceId || null,
68
+ projectName: project.projectName || null,
69
+ appKey: project.appKey || null,
70
+ confidence: Number(bestScore.toFixed(2)),
71
+ reasonCode
72
+ };
73
+ }
74
+
75
+ function buildResolutionCallerContext(options = {}, portfolio = {}) {
76
+ const portfolioContext = portfolio && portfolio.callerContext && typeof portfolio.callerContext === 'object'
77
+ ? portfolio.callerContext
78
+ : {};
79
+ const explicitCurrentProject = normalizeString(options.currentProject);
80
+ const explicitDeviceId = normalizeString(options.device);
81
+ const explicitToolInstanceId = normalizeString(options.toolInstanceId);
82
+
83
+ return {
84
+ ...(explicitCurrentProject || portfolioContext.projectId
85
+ ? { currentProjectId: explicitCurrentProject || portfolioContext.projectId }
86
+ : {}),
87
+ ...(portfolioContext.workspaceId ? { workspaceId: portfolioContext.workspaceId } : {}),
88
+ ...(explicitDeviceId || portfolioContext.deviceId
89
+ ? { deviceId: explicitDeviceId || portfolioContext.deviceId }
90
+ : {}),
91
+ ...(explicitToolInstanceId ? { toolInstanceId: explicitToolInstanceId } : {})
92
+ };
93
+ }
94
+
95
+ async function resolveProjectTarget(options = {}, dependencies = {}) {
96
+ const requestText = normalizeString(options.request);
97
+ const portfolio = await buildProjectPortfolioProjection({
98
+ workspace: options.workspace
99
+ }, dependencies);
100
+ const callerContext = buildResolutionCallerContext(options, portfolio);
101
+ const currentProjectId = normalizeString(callerContext.currentProjectId);
102
+ const visibleProjects = Array.isArray(portfolio.projects) ? portfolio.projects : [];
103
+ const currentProject = visibleProjects.find((project) => project.projectId === currentProjectId) || null;
104
+
105
+ if (!requestText) {
106
+ if (currentProject) {
107
+ return {
108
+ resolvedAt: new Date().toISOString(),
109
+ callerContext,
110
+ status: 'current-project',
111
+ currentProjectId,
112
+ resolvedProjectId: currentProjectId,
113
+ confidence: 1,
114
+ reasonCode: 'target.current_project'
115
+ };
116
+ }
117
+ return {
118
+ resolvedAt: new Date().toISOString(),
119
+ callerContext,
120
+ status: 'unresolved',
121
+ ...(currentProjectId ? { currentProjectId } : {}),
122
+ reasonCode: currentProjectId
123
+ ? 'target.current_project_unavailable'
124
+ : 'target.no_request_or_current_project'
125
+ };
126
+ }
127
+
128
+ const matches = visibleProjects
129
+ .map((project) => scoreProjectMatch(requestText, project))
130
+ .filter(Boolean)
131
+ .sort((left, right) => {
132
+ if (right.confidence !== left.confidence) {
133
+ return right.confidence - left.confidence;
134
+ }
135
+ return `${left.projectId}`.localeCompare(`${right.projectId}`);
136
+ });
137
+
138
+ if (matches.length === 0) {
139
+ return {
140
+ resolvedAt: new Date().toISOString(),
141
+ callerContext,
142
+ status: 'unresolved',
143
+ ...(currentProjectId ? { currentProjectId } : {}),
144
+ reasonCode: 'target.no_match'
145
+ };
146
+ }
147
+
148
+ const best = matches[0];
149
+ const second = matches[1];
150
+ const ambiguous = second && Math.abs(best.confidence - second.confidence) < 0.05;
151
+
152
+ if (ambiguous) {
153
+ return {
154
+ resolvedAt: new Date().toISOString(),
155
+ callerContext,
156
+ status: 'ambiguous',
157
+ ...(currentProjectId ? { currentProjectId } : {}),
158
+ confidence: best.confidence,
159
+ reasonCode: 'target.ambiguous',
160
+ candidates: matches.slice(0, 5)
161
+ };
162
+ }
163
+
164
+ return {
165
+ resolvedAt: new Date().toISOString(),
166
+ callerContext,
167
+ status: currentProjectId && best.projectId === currentProjectId
168
+ ? 'current-project'
169
+ : 'resolved-other-project',
170
+ ...(currentProjectId ? { currentProjectId } : {}),
171
+ resolvedProjectId: best.projectId,
172
+ confidence: best.confidence,
173
+ reasonCode: best.reasonCode,
174
+ candidates: [best]
175
+ };
176
+ }
177
+
178
+ module.exports = {
179
+ resolveProjectTarget
180
+ };