scene-capability-engine 3.6.32 → 3.6.36

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 (83) hide show
  1. package/CHANGELOG.md +86 -1
  2. package/README.md +119 -122
  3. package/README.zh.md +123 -121
  4. package/bin/scene-capability-engine.js +11 -0
  5. package/docs/README.md +21 -32
  6. package/docs/auto-refactor-index.md +384 -0
  7. package/docs/command-reference.md +94 -2
  8. package/docs/magicball-adaptation-task-checklist-v1.md +385 -0
  9. package/docs/magicball-app-bundle-sqlite-and-command-draft.md +539 -0
  10. package/docs/magicball-capability-iteration-api.md +2 -0
  11. package/docs/magicball-capability-iteration-ui.md +2 -0
  12. package/docs/magicball-capability-library.md +2 -0
  13. package/docs/magicball-cli-invocation-examples.md +336 -0
  14. package/docs/magicball-frontend-state-and-command-mapping.md +244 -0
  15. package/docs/magicball-integration-doc-index.md +137 -0
  16. package/docs/magicball-integration-issue-tracker.md +218 -0
  17. package/docs/magicball-mode-home-and-ontology-empty-state-playbook.md +249 -0
  18. package/docs/magicball-sce-adaptation-guide.md +203 -0
  19. package/docs/magicball-three-mode-alignment-plan.md +551 -0
  20. package/docs/magicball-ui-surface-checklist.md +126 -0
  21. package/docs/magicball-write-auth-adaptation-guide.md +328 -0
  22. package/docs/refactor-completion-roadmap.md +116 -0
  23. package/docs/zh/README.md +27 -30
  24. package/docs/zh/refactor-completion-roadmap.md +116 -0
  25. package/lib/app/registry-config.js +73 -0
  26. package/lib/app/registry-sync-service.js +228 -0
  27. package/lib/auto/archive-schema-service.js +276 -0
  28. package/lib/auto/archive-summary.js +60 -0
  29. package/lib/auto/batch-goal-input-service.js +543 -0
  30. package/lib/auto/batch-output.js +201 -0
  31. package/lib/auto/batch-summary-storage-service.js +110 -0
  32. package/lib/auto/close-loop-batch-service.js +116 -0
  33. package/lib/auto/close-loop-controller-service.js +287 -0
  34. package/lib/auto/close-loop-program-service.js +283 -0
  35. package/lib/auto/close-loop-recovery-service.js +191 -0
  36. package/lib/auto/close-loop-session-storage-service.js +50 -0
  37. package/lib/auto/controller-lock-service.js +55 -0
  38. package/lib/auto/controller-output.js +32 -0
  39. package/lib/auto/controller-queue-service.js +127 -0
  40. package/lib/auto/controller-session-storage-service.js +105 -0
  41. package/lib/auto/governance-advisory-service.js +208 -0
  42. package/lib/auto/governance-close-loop-service.js +411 -0
  43. package/lib/auto/governance-maintenance-presenter.js +162 -0
  44. package/lib/auto/governance-maintenance-service.js +112 -0
  45. package/lib/auto/governance-session-presenter.js +70 -0
  46. package/lib/auto/governance-session-storage-service.js +198 -0
  47. package/lib/auto/governance-signals.js +139 -0
  48. package/lib/auto/governance-stats-presenter.js +337 -0
  49. package/lib/auto/governance-stats-service.js +115 -0
  50. package/lib/auto/governance-summary.js +703 -0
  51. package/lib/auto/handoff-capability-matrix-service.js +281 -0
  52. package/lib/auto/handoff-evidence-review-service.js +251 -0
  53. package/lib/auto/handoff-release-evidence-service.js +190 -0
  54. package/lib/auto/handoff-release-gate-history-loaders-service.js +502 -0
  55. package/lib/auto/handoff-release-gate-history-service.js +257 -0
  56. package/lib/auto/handoff-reporting-service.js +1407 -0
  57. package/lib/auto/handoff-run-service.js +486 -0
  58. package/lib/auto/handoff-snapshots-service.js +645 -0
  59. package/lib/auto/observability-service.js +132 -0
  60. package/lib/auto/output-writer.js +34 -0
  61. package/lib/auto/program-auto-remediation-service.js +130 -0
  62. package/lib/auto/program-diagnostics.js +138 -0
  63. package/lib/auto/program-governance-helpers.js +306 -0
  64. package/lib/auto/program-governance-loop-service.js +413 -0
  65. package/lib/auto/program-output.js +106 -0
  66. package/lib/auto/program-summary.js +183 -0
  67. package/lib/auto/recovery-memory-service.js +684 -0
  68. package/lib/auto/recovery-selection-service.js +52 -0
  69. package/lib/auto/retention-policy.js +98 -0
  70. package/lib/auto/session-persistence-service.js +106 -0
  71. package/lib/auto/session-presenter.js +105 -0
  72. package/lib/auto/session-prune-service.js +190 -0
  73. package/lib/auto/session-query-service.js +249 -0
  74. package/lib/auto/spec-protection.js +141 -0
  75. package/lib/commands/app.js +911 -0
  76. package/lib/commands/assurance.js +212 -0
  77. package/lib/commands/auto.js +1091 -11063
  78. package/lib/commands/mode.js +321 -0
  79. package/lib/commands/ontology.js +415 -0
  80. package/lib/commands/pm.js +422 -0
  81. package/lib/ontology/seed-profiles.js +160 -0
  82. package/lib/state/sce-state-store.js +3369 -1200
  83. package/package.json +1 -1
@@ -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
+ };