scene-capability-engine 3.6.32 → 3.6.37
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 +109 -11
- package/README.md +119 -122
- package/README.zh.md +123 -121
- package/bin/scene-capability-engine.js +12 -1
- package/docs/331-poc-adaptation-roadmap.md +3 -3
- package/docs/README.md +21 -32
- package/docs/auto-refactor-index.md +384 -0
- package/docs/command-reference.md +99 -7
- package/docs/faq.md +1 -1
- package/docs/interactive-customization/331-poc-sce-integration-checklist.md +3 -3
- package/docs/interactive-customization/moqui-interactive-template-playbook.md +4 -4
- package/docs/interactive-customization/phase-acceptance-evidence.md +2 -2
- package/docs/magicball-adaptation-task-checklist-v1.md +385 -0
- package/docs/magicball-app-bundle-sqlite-and-command-draft.md +539 -0
- package/docs/magicball-capability-iteration-api.md +2 -0
- package/docs/magicball-capability-iteration-ui.md +2 -0
- package/docs/magicball-capability-library.md +2 -0
- package/docs/magicball-cli-invocation-examples.md +336 -0
- package/docs/magicball-frontend-state-and-command-mapping.md +244 -0
- package/docs/magicball-integration-doc-index.md +137 -0
- package/docs/magicball-integration-issue-tracker.md +218 -0
- package/docs/magicball-mode-home-and-ontology-empty-state-playbook.md +249 -0
- package/docs/magicball-sce-adaptation-guide.md +203 -0
- package/docs/magicball-three-mode-alignment-plan.md +551 -0
- package/docs/magicball-ui-surface-checklist.md +126 -0
- package/docs/magicball-write-auth-adaptation-guide.md +328 -0
- package/docs/moqui-standard-rebuild-guide.md +6 -6
- package/docs/moqui-template-core-library-playbook.md +1 -1
- package/docs/refactor-completion-roadmap.md +116 -0
- package/docs/release-checklist.md +50 -27
- package/docs/releases/README.md +1 -0
- package/docs/releases/v3.6.37.md +22 -0
- package/docs/steering-strategy-guide.md +7 -7
- package/docs/troubleshooting.md +1 -1
- package/docs/zh/README.md +27 -30
- package/docs/zh/refactor-completion-roadmap.md +116 -0
- package/docs/zh/release-checklist.md +40 -17
- package/docs/zh/releases/README.md +1 -0
- package/docs/zh/releases/v3.6.37.md +22 -0
- package/lib/app/registry-config.js +73 -0
- package/lib/app/registry-sync-service.js +228 -0
- package/lib/auto/archive-schema-service.js +276 -0
- package/lib/auto/archive-summary.js +60 -0
- package/lib/auto/batch-goal-input-service.js +543 -0
- package/lib/auto/batch-output.js +201 -0
- package/lib/auto/batch-summary-storage-service.js +110 -0
- package/lib/auto/close-loop-batch-service.js +116 -0
- package/lib/auto/close-loop-controller-service.js +287 -0
- package/lib/auto/close-loop-program-service.js +283 -0
- package/lib/auto/close-loop-recovery-service.js +191 -0
- package/lib/auto/close-loop-session-storage-service.js +50 -0
- package/lib/auto/controller-lock-service.js +55 -0
- package/lib/auto/controller-output.js +32 -0
- package/lib/auto/controller-queue-service.js +127 -0
- package/lib/auto/controller-session-storage-service.js +105 -0
- package/lib/auto/governance-advisory-service.js +208 -0
- package/lib/auto/governance-close-loop-service.js +411 -0
- package/lib/auto/governance-maintenance-presenter.js +162 -0
- package/lib/auto/governance-maintenance-service.js +112 -0
- package/lib/auto/governance-session-presenter.js +70 -0
- package/lib/auto/governance-session-storage-service.js +198 -0
- package/lib/auto/governance-signals.js +139 -0
- package/lib/auto/governance-stats-presenter.js +337 -0
- package/lib/auto/governance-stats-service.js +115 -0
- package/lib/auto/governance-summary.js +703 -0
- package/lib/auto/handoff-capability-matrix-service.js +281 -0
- package/lib/auto/handoff-evidence-review-service.js +251 -0
- package/lib/auto/handoff-release-evidence-service.js +190 -0
- package/lib/auto/handoff-release-gate-history-loaders-service.js +502 -0
- package/lib/auto/handoff-release-gate-history-service.js +257 -0
- package/lib/auto/handoff-reporting-service.js +1407 -0
- package/lib/auto/handoff-run-service.js +486 -0
- package/lib/auto/handoff-snapshots-service.js +645 -0
- package/lib/auto/observability-service.js +132 -0
- package/lib/auto/output-writer.js +34 -0
- package/lib/auto/program-auto-remediation-service.js +130 -0
- package/lib/auto/program-diagnostics.js +138 -0
- package/lib/auto/program-governance-helpers.js +306 -0
- package/lib/auto/program-governance-loop-service.js +413 -0
- package/lib/auto/program-output.js +106 -0
- package/lib/auto/program-summary.js +183 -0
- package/lib/auto/recovery-memory-service.js +684 -0
- package/lib/auto/recovery-selection-service.js +52 -0
- package/lib/auto/retention-policy.js +98 -0
- package/lib/auto/session-persistence-service.js +106 -0
- package/lib/auto/session-presenter.js +105 -0
- package/lib/auto/session-prune-service.js +190 -0
- package/lib/auto/session-query-service.js +249 -0
- package/lib/auto/spec-protection.js +141 -0
- package/lib/commands/adopt.js +4 -4
- package/lib/commands/app.js +911 -0
- package/lib/commands/assurance.js +212 -0
- package/lib/commands/auto.js +1093 -11065
- package/lib/commands/mode.js +321 -0
- package/lib/commands/ontology.js +415 -0
- package/lib/commands/pm.js +422 -0
- package/lib/ontology/seed-profiles.js +160 -0
- package/lib/spec/bootstrap/context-collector.js +1 -1
- package/lib/state/sce-state-store.js +3369 -1200
- package/lib/steering/adoption-config.js +2 -2
- package/lib/steering/compliance-cache.js +2 -2
- package/lib/steering/steering-manager.js +4 -4
- package/lib/task/task-claimer.js +1 -2
- package/lib/workspace/multi/workspace-context-resolver.js +3 -3
- package/lib/workspace/multi/workspace-state-manager.js +0 -164
- package/lib/workspace/sce-tracking-audit.js +1 -1
- package/lib/workspace/takeover-baseline.js +1 -1
- package/package.json +1 -1
- package/template/.sce/README.md +1 -1
- package/template/.sce/steering/CORE_PRINCIPLES.md +1 -1
- package/bin/kse.js +0 -3
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
async function listCloseLoopSessions(projectPath, options = {}, dependencies = {}) {
|
|
2
|
+
const {
|
|
3
|
+
readCloseLoopSessionEntries,
|
|
4
|
+
normalizeStatusFilter,
|
|
5
|
+
filterEntriesByStatus,
|
|
6
|
+
normalizeLimit,
|
|
7
|
+
presentCloseLoopSessionList,
|
|
8
|
+
buildStatusCounts,
|
|
9
|
+
getCloseLoopSessionDir
|
|
10
|
+
} = dependencies;
|
|
11
|
+
const sessions = await readCloseLoopSessionEntries(projectPath);
|
|
12
|
+
const statusFilter = normalizeStatusFilter(options.status);
|
|
13
|
+
const filteredSessions = filterEntriesByStatus(sessions, statusFilter);
|
|
14
|
+
const limit = normalizeLimit(options.limit, 20);
|
|
15
|
+
return presentCloseLoopSessionList(
|
|
16
|
+
projectPath,
|
|
17
|
+
filteredSessions,
|
|
18
|
+
statusFilter,
|
|
19
|
+
limit,
|
|
20
|
+
buildStatusCounts,
|
|
21
|
+
getCloseLoopSessionDir
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function statsCloseLoopSessions(projectPath, options = {}, dependencies = {}) {
|
|
26
|
+
const {
|
|
27
|
+
readCloseLoopSessionEntries,
|
|
28
|
+
normalizeStatsWindowDays,
|
|
29
|
+
normalizeStatusFilter,
|
|
30
|
+
filterEntriesByStatus,
|
|
31
|
+
presentCloseLoopSessionStats,
|
|
32
|
+
buildStatusCounts,
|
|
33
|
+
buildMasterSpecCounts,
|
|
34
|
+
isFailedStatus,
|
|
35
|
+
getCloseLoopSessionDir,
|
|
36
|
+
now = () => Date.now()
|
|
37
|
+
} = dependencies;
|
|
38
|
+
const sessions = await readCloseLoopSessionEntries(projectPath);
|
|
39
|
+
const days = normalizeStatsWindowDays(options.days);
|
|
40
|
+
const statusFilter = normalizeStatusFilter(options.status);
|
|
41
|
+
const nowMs = typeof now === 'function' ? Number(now()) : Date.now();
|
|
42
|
+
const cutoffMs = days === null ? null : nowMs - (days * 24 * 60 * 60 * 1000);
|
|
43
|
+
const withinWindow = sessions.filter((session) => cutoffMs === null || Number(session && session.mtime_ms) >= cutoffMs);
|
|
44
|
+
const filteredSessions = filterEntriesByStatus(withinWindow, statusFilter);
|
|
45
|
+
return presentCloseLoopSessionStats(
|
|
46
|
+
getCloseLoopSessionDir(projectPath),
|
|
47
|
+
filteredSessions,
|
|
48
|
+
statusFilter,
|
|
49
|
+
days,
|
|
50
|
+
cutoffMs,
|
|
51
|
+
buildStatusCounts,
|
|
52
|
+
buildMasterSpecCounts,
|
|
53
|
+
isFailedStatus
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function listGovernanceCloseLoopSessions(projectPath, options = {}, dependencies = {}) {
|
|
58
|
+
const {
|
|
59
|
+
readGovernanceCloseLoopSessionEntries,
|
|
60
|
+
normalizeStatusFilter,
|
|
61
|
+
filterEntriesByStatus,
|
|
62
|
+
filterGovernanceEntriesByResumeMode,
|
|
63
|
+
normalizeLimit,
|
|
64
|
+
presentGovernanceSessionList,
|
|
65
|
+
buildStatusCounts,
|
|
66
|
+
getGovernanceCloseLoopSessionDir
|
|
67
|
+
} = dependencies;
|
|
68
|
+
const sessions = await readGovernanceCloseLoopSessionEntries(projectPath);
|
|
69
|
+
const statusFilter = normalizeStatusFilter(options.status);
|
|
70
|
+
const resumeOnly = Boolean(options.resumeOnly);
|
|
71
|
+
const statusFiltered = filterEntriesByStatus(sessions, statusFilter);
|
|
72
|
+
const filteredSessions = filterGovernanceEntriesByResumeMode(statusFiltered, resumeOnly);
|
|
73
|
+
const limit = normalizeLimit(options.limit, 20);
|
|
74
|
+
return presentGovernanceSessionList(
|
|
75
|
+
projectPath,
|
|
76
|
+
filteredSessions,
|
|
77
|
+
statusFilter,
|
|
78
|
+
resumeOnly,
|
|
79
|
+
buildStatusCounts,
|
|
80
|
+
getGovernanceCloseLoopSessionDir,
|
|
81
|
+
limit
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function statsGovernanceCloseLoopSessions(projectPath, options = {}, dependencies = {}) {
|
|
86
|
+
const {
|
|
87
|
+
readGovernanceCloseLoopSessionEntries,
|
|
88
|
+
normalizeStatsWindowDays,
|
|
89
|
+
normalizeStatusFilter,
|
|
90
|
+
filterEntriesByStatus,
|
|
91
|
+
filterGovernanceEntriesByResumeMode,
|
|
92
|
+
presentGovernanceSessionStats,
|
|
93
|
+
normalizeStatusToken,
|
|
94
|
+
isCompletedStatus,
|
|
95
|
+
isFailedStatus,
|
|
96
|
+
calculatePercent,
|
|
97
|
+
toGovernanceReleaseGateNumber,
|
|
98
|
+
getGovernanceCloseLoopSessionDir,
|
|
99
|
+
buildStatusCounts,
|
|
100
|
+
parseAutoHandoffGateBoolean,
|
|
101
|
+
now = () => Date.now()
|
|
102
|
+
} = dependencies;
|
|
103
|
+
const sessions = await readGovernanceCloseLoopSessionEntries(projectPath);
|
|
104
|
+
const days = normalizeStatsWindowDays(options.days);
|
|
105
|
+
const statusFilter = normalizeStatusFilter(options.status);
|
|
106
|
+
const resumeOnly = Boolean(options.resumeOnly);
|
|
107
|
+
const nowMs = typeof now === 'function' ? Number(now()) : Date.now();
|
|
108
|
+
const cutoffMs = days === null ? null : nowMs - (days * 24 * 60 * 60 * 1000);
|
|
109
|
+
const withinWindow = sessions.filter((session) => cutoffMs === null || Number(session && session.mtime_ms) >= cutoffMs);
|
|
110
|
+
const statusFiltered = filterEntriesByStatus(withinWindow, statusFilter);
|
|
111
|
+
const filteredSessions = filterGovernanceEntriesByResumeMode(statusFiltered, resumeOnly);
|
|
112
|
+
return presentGovernanceSessionStats(projectPath, filteredSessions, {
|
|
113
|
+
days,
|
|
114
|
+
status_filter: statusFilter,
|
|
115
|
+
resume_only: resumeOnly,
|
|
116
|
+
cutoff_ms: cutoffMs
|
|
117
|
+
}, {
|
|
118
|
+
normalizeStatusToken,
|
|
119
|
+
isCompletedStatus,
|
|
120
|
+
isFailedStatus,
|
|
121
|
+
calculatePercent,
|
|
122
|
+
toGovernanceReleaseGateNumber,
|
|
123
|
+
getGovernanceCloseLoopSessionDir,
|
|
124
|
+
buildStatusCounts,
|
|
125
|
+
parseAutoHandoffGateBoolean
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function listCloseLoopControllerSessions(projectPath, options = {}, dependencies = {}) {
|
|
130
|
+
const {
|
|
131
|
+
readCloseLoopControllerSessionEntries,
|
|
132
|
+
normalizeStatusFilter,
|
|
133
|
+
filterEntriesByStatus,
|
|
134
|
+
normalizeLimit,
|
|
135
|
+
presentControllerSessionList,
|
|
136
|
+
buildStatusCounts,
|
|
137
|
+
getCloseLoopControllerSessionDir
|
|
138
|
+
} = dependencies;
|
|
139
|
+
const sessions = await readCloseLoopControllerSessionEntries(projectPath);
|
|
140
|
+
const statusFilter = normalizeStatusFilter(options.status);
|
|
141
|
+
const filteredSessions = filterEntriesByStatus(sessions, statusFilter);
|
|
142
|
+
const limit = normalizeLimit(options.limit, 20);
|
|
143
|
+
return presentControllerSessionList(
|
|
144
|
+
projectPath,
|
|
145
|
+
filteredSessions,
|
|
146
|
+
statusFilter,
|
|
147
|
+
limit,
|
|
148
|
+
buildStatusCounts,
|
|
149
|
+
getCloseLoopControllerSessionDir
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function statsCloseLoopControllerSessions(projectPath, options = {}, dependencies = {}) {
|
|
154
|
+
const {
|
|
155
|
+
readCloseLoopControllerSessionEntries,
|
|
156
|
+
normalizeStatsWindowDays,
|
|
157
|
+
normalizeStatusFilter,
|
|
158
|
+
filterEntriesByStatus,
|
|
159
|
+
normalizeStatusToken,
|
|
160
|
+
isFailedStatus,
|
|
161
|
+
buildStatusCounts,
|
|
162
|
+
buildQueueFormatCounts,
|
|
163
|
+
getCloseLoopControllerSessionDir,
|
|
164
|
+
now = () => Date.now()
|
|
165
|
+
} = dependencies;
|
|
166
|
+
const sessions = await readCloseLoopControllerSessionEntries(projectPath);
|
|
167
|
+
const days = normalizeStatsWindowDays(options.days);
|
|
168
|
+
const statusFilter = normalizeStatusFilter(options.status);
|
|
169
|
+
const nowMs = typeof now === 'function' ? Number(now()) : Date.now();
|
|
170
|
+
const cutoffMs = days === null ? null : nowMs - (days * 24 * 60 * 60 * 1000);
|
|
171
|
+
const withinWindow = sessions.filter((session) => cutoffMs === null || Number(session && session.mtime_ms) >= cutoffMs);
|
|
172
|
+
const filteredSessions = filterEntriesByStatus(withinWindow, statusFilter);
|
|
173
|
+
|
|
174
|
+
let completedSessions = 0;
|
|
175
|
+
let failedSessions = 0;
|
|
176
|
+
let processedGoalsSum = 0;
|
|
177
|
+
let pendingGoalsSum = 0;
|
|
178
|
+
let sessionsWithProcessed = 0;
|
|
179
|
+
let sessionsWithPending = 0;
|
|
180
|
+
|
|
181
|
+
for (const session of filteredSessions) {
|
|
182
|
+
const status = normalizeStatusToken(session && session.status) || 'unknown';
|
|
183
|
+
if (status === 'completed') {
|
|
184
|
+
completedSessions += 1;
|
|
185
|
+
}
|
|
186
|
+
if (isFailedStatus(status)) {
|
|
187
|
+
failedSessions += 1;
|
|
188
|
+
}
|
|
189
|
+
const processedGoals = Number(session && session.processed_goals);
|
|
190
|
+
if (Number.isFinite(processedGoals)) {
|
|
191
|
+
processedGoalsSum += processedGoals;
|
|
192
|
+
sessionsWithProcessed += 1;
|
|
193
|
+
}
|
|
194
|
+
const pendingGoals = Number(session && session.pending_goals);
|
|
195
|
+
if (Number.isFinite(pendingGoals)) {
|
|
196
|
+
pendingGoalsSum += pendingGoals;
|
|
197
|
+
sessionsWithPending += 1;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const totalSessions = filteredSessions.length;
|
|
202
|
+
const completionRate = totalSessions > 0 ? Number(((completedSessions / totalSessions) * 100).toFixed(2)) : 0;
|
|
203
|
+
const failureRate = totalSessions > 0 ? Number(((failedSessions / totalSessions) * 100).toFixed(2)) : 0;
|
|
204
|
+
const latestSession = totalSessions > 0 ? filteredSessions[0] : null;
|
|
205
|
+
const oldestSession = totalSessions > 0 ? filteredSessions[totalSessions - 1] : null;
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
mode: 'auto-controller-session-stats',
|
|
209
|
+
session_dir: getCloseLoopControllerSessionDir(projectPath),
|
|
210
|
+
criteria: {
|
|
211
|
+
days,
|
|
212
|
+
status_filter: statusFilter,
|
|
213
|
+
since: cutoffMs === null ? null : new Date(cutoffMs).toISOString()
|
|
214
|
+
},
|
|
215
|
+
total_sessions: totalSessions,
|
|
216
|
+
completed_sessions: completedSessions,
|
|
217
|
+
failed_sessions: failedSessions,
|
|
218
|
+
completion_rate_percent: completionRate,
|
|
219
|
+
failure_rate_percent: failureRate,
|
|
220
|
+
processed_goals_sum: processedGoalsSum,
|
|
221
|
+
pending_goals_sum: pendingGoalsSum,
|
|
222
|
+
average_processed_goals_per_session: sessionsWithProcessed > 0 ? Number((processedGoalsSum / sessionsWithProcessed).toFixed(2)) : 0,
|
|
223
|
+
average_pending_goals_per_session: sessionsWithPending > 0 ? Number((pendingGoalsSum / sessionsWithPending).toFixed(2)) : 0,
|
|
224
|
+
status_counts: buildStatusCounts(filteredSessions),
|
|
225
|
+
queue_format_counts: buildQueueFormatCounts(filteredSessions),
|
|
226
|
+
latest_updated_at: latestSession ? latestSession.updated_at : null,
|
|
227
|
+
oldest_updated_at: oldestSession ? oldestSession.updated_at : null,
|
|
228
|
+
latest_sessions: filteredSessions.slice(0, 10).map((item) => ({
|
|
229
|
+
id: item.id,
|
|
230
|
+
status: item.status,
|
|
231
|
+
queue_file: item.queue_file,
|
|
232
|
+
queue_format: item.queue_format,
|
|
233
|
+
processed_goals: item.processed_goals,
|
|
234
|
+
pending_goals: item.pending_goals,
|
|
235
|
+
updated_at: item.updated_at,
|
|
236
|
+
parse_error: item.parse_error
|
|
237
|
+
}))
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
module.exports = {
|
|
242
|
+
listCloseLoopSessions,
|
|
243
|
+
statsCloseLoopSessions,
|
|
244
|
+
listGovernanceCloseLoopSessions,
|
|
245
|
+
statsGovernanceCloseLoopSessions,
|
|
246
|
+
listCloseLoopControllerSessions,
|
|
247
|
+
statsCloseLoopControllerSessions
|
|
248
|
+
};
|
|
249
|
+
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
function normalizeStatusToken(statusCandidate) {
|
|
2
|
+
return String(statusCandidate || '').trim().toLowerCase();
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function collectSpecNamesFromBatchSummary(summary) {
|
|
6
|
+
const names = new Set();
|
|
7
|
+
const results = Array.isArray(summary && summary.results) ? summary.results : [];
|
|
8
|
+
for (const item of results) {
|
|
9
|
+
const masterSpec = String(item && item.master_spec ? item.master_spec : '').trim();
|
|
10
|
+
if (masterSpec) {
|
|
11
|
+
names.add(masterSpec);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return [...names];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function collectSpecNamesFromCloseLoopSessionPayload(payload) {
|
|
18
|
+
const names = new Set();
|
|
19
|
+
const portfolio = payload && payload.portfolio && typeof payload.portfolio === 'object'
|
|
20
|
+
? payload.portfolio
|
|
21
|
+
: {};
|
|
22
|
+
const masterSpec = String(portfolio.master_spec || '').trim();
|
|
23
|
+
if (masterSpec) {
|
|
24
|
+
names.add(masterSpec);
|
|
25
|
+
}
|
|
26
|
+
const subSpecs = Array.isArray(portfolio.sub_specs) ? portfolio.sub_specs : [];
|
|
27
|
+
for (const item of subSpecs) {
|
|
28
|
+
const specName = String(item || '').trim();
|
|
29
|
+
if (specName) {
|
|
30
|
+
names.add(specName);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return names;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function collectSpecNamesFromBatchSummaryPayload(payload, includeCompleted = false) {
|
|
37
|
+
const names = new Set();
|
|
38
|
+
const results = Array.isArray(payload && payload.results) ? payload.results : [];
|
|
39
|
+
for (const item of results) {
|
|
40
|
+
const status = normalizeStatusToken(item && item.status);
|
|
41
|
+
if (!includeCompleted && status === 'completed') {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const masterSpec = String(item && item.master_spec ? item.master_spec : '').trim();
|
|
45
|
+
if (masterSpec) {
|
|
46
|
+
names.add(masterSpec);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return names;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function createProtectionReasonRecord() {
|
|
53
|
+
return {
|
|
54
|
+
additional: 0,
|
|
55
|
+
collaboration_active: 0,
|
|
56
|
+
close_loop_session_recent_or_incomplete: 0,
|
|
57
|
+
batch_summary_recent_or_incomplete: 0,
|
|
58
|
+
controller_session_recent_or_incomplete: 0,
|
|
59
|
+
total_references: 0
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function ensureProtectionReasonRecord(reasonMap, specName) {
|
|
64
|
+
const key = String(specName || '').trim();
|
|
65
|
+
if (!key) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (!reasonMap.has(key)) {
|
|
69
|
+
reasonMap.set(key, createProtectionReasonRecord());
|
|
70
|
+
}
|
|
71
|
+
return reasonMap.get(key);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function incrementProtectionReason(reasonMap, specName, reasonKey, delta = 1) {
|
|
75
|
+
if (!Number.isFinite(delta) || delta <= 0) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const record = ensureProtectionReasonRecord(reasonMap, specName);
|
|
79
|
+
if (!record) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const normalizedReason = String(reasonKey || '').trim();
|
|
83
|
+
if (!normalizedReason || !Object.prototype.hasOwnProperty.call(record, normalizedReason)) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
record[normalizedReason] += delta;
|
|
87
|
+
record.total_references += delta;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function buildProtectionRanking(reasonMap) {
|
|
91
|
+
const entries = [];
|
|
92
|
+
for (const [spec, reasons] of reasonMap.entries()) {
|
|
93
|
+
entries.push({
|
|
94
|
+
spec,
|
|
95
|
+
total_references: Number(reasons.total_references) || 0,
|
|
96
|
+
reasons: {
|
|
97
|
+
additional: Number(reasons.additional) || 0,
|
|
98
|
+
collaboration_active: Number(reasons.collaboration_active) || 0,
|
|
99
|
+
close_loop_session_recent_or_incomplete: Number(reasons.close_loop_session_recent_or_incomplete) || 0,
|
|
100
|
+
batch_summary_recent_or_incomplete: Number(reasons.batch_summary_recent_or_incomplete) || 0,
|
|
101
|
+
controller_session_recent_or_incomplete: Number(reasons.controller_session_recent_or_incomplete) || 0
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
entries.sort((left, right) => {
|
|
106
|
+
if (right.total_references !== left.total_references) {
|
|
107
|
+
return right.total_references - left.total_references;
|
|
108
|
+
}
|
|
109
|
+
return left.spec.localeCompare(right.spec);
|
|
110
|
+
});
|
|
111
|
+
return entries;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function buildSpecProtectionReasonPayload(specName, reasonMap) {
|
|
115
|
+
if (!reasonMap || typeof reasonMap.get !== 'function') {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
const record = reasonMap.get(specName);
|
|
119
|
+
if (!record) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
total_references: Number(record.total_references) || 0,
|
|
124
|
+
additional: Number(record.additional) || 0,
|
|
125
|
+
collaboration_active: Number(record.collaboration_active) || 0,
|
|
126
|
+
close_loop_session_recent_or_incomplete: Number(record.close_loop_session_recent_or_incomplete) || 0,
|
|
127
|
+
batch_summary_recent_or_incomplete: Number(record.batch_summary_recent_or_incomplete) || 0,
|
|
128
|
+
controller_session_recent_or_incomplete: Number(record.controller_session_recent_or_incomplete) || 0
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = {
|
|
133
|
+
collectSpecNamesFromBatchSummary,
|
|
134
|
+
collectSpecNamesFromCloseLoopSessionPayload,
|
|
135
|
+
collectSpecNamesFromBatchSummaryPayload,
|
|
136
|
+
createProtectionReasonRecord,
|
|
137
|
+
ensureProtectionReasonRecord,
|
|
138
|
+
incrementProtectionReason,
|
|
139
|
+
buildProtectionRanking,
|
|
140
|
+
buildSpecProtectionReasonPayload
|
|
141
|
+
};
|
package/lib/commands/adopt.js
CHANGED
|
@@ -449,7 +449,7 @@ async function adoptInteractive(projectPath, options) {
|
|
|
449
449
|
// Prompt for strategy
|
|
450
450
|
steeringStrategy = await steeringManager.promptStrategy(detection.steeringDetection);
|
|
451
451
|
|
|
452
|
-
if (steeringStrategy === 'use-
|
|
452
|
+
if (steeringStrategy === 'use-sce') {
|
|
453
453
|
// Backup existing steering files
|
|
454
454
|
console.log(chalk.blue('📦 Backing up existing steering files...'));
|
|
455
455
|
const backupResult = await steeringManager.backupSteering(projectPath);
|
|
@@ -460,7 +460,7 @@ async function adoptInteractive(projectPath, options) {
|
|
|
460
460
|
|
|
461
461
|
// Install sce steering files
|
|
462
462
|
console.log(chalk.blue('📝 Installing sce steering files...'));
|
|
463
|
-
const installResult = await steeringManager.
|
|
463
|
+
const installResult = await steeringManager.installSceSteering(projectPath);
|
|
464
464
|
|
|
465
465
|
if (installResult.success) {
|
|
466
466
|
console.log(chalk.green(`✅ Installed ${installResult.filesInstalled} sce steering file(s)`));
|
|
@@ -711,7 +711,7 @@ async function adoptInteractive(projectPath, options) {
|
|
|
711
711
|
*
|
|
712
712
|
* @param {string} projectPath - Project root path
|
|
713
713
|
*/
|
|
714
|
-
async function
|
|
714
|
+
async function setupSceMcpConfig(projectPath) {
|
|
715
715
|
const mcpConfigPath = path.join(projectPath, '.sce', 'settings', 'mcp.json');
|
|
716
716
|
|
|
717
717
|
// Don't overwrite existing config
|
|
@@ -767,7 +767,7 @@ async function offerAutomationSetup(projectPath) {
|
|
|
767
767
|
|
|
768
768
|
// If AI IDE detected, create default MCP settings
|
|
769
769
|
if (toolDetection.primaryTool === 'SCE') {
|
|
770
|
-
await
|
|
770
|
+
await setupSceMcpConfig(projectPath);
|
|
771
771
|
}
|
|
772
772
|
} catch (toolError) {
|
|
773
773
|
// Tool detection is optional, don't fail adoption if it errors
|