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,306 @@
1
+ function normalizeProgramGateFallbackProfile(profileCandidate, dependencies = {}) {
2
+ const PROGRAM_GATE_PROFILE_POLICY = dependencies.PROGRAM_GATE_PROFILE_POLICY || {};
3
+ const normalized = typeof profileCandidate === 'string'
4
+ ? profileCandidate.trim().toLowerCase()
5
+ : 'none';
6
+ if (normalized === 'none') {
7
+ return 'none';
8
+ }
9
+ if (!PROGRAM_GATE_PROFILE_POLICY[normalized]) {
10
+ throw new Error('--program-gate-fallback-profile must be one of: none, default, dev, staging, prod.');
11
+ }
12
+ return normalized;
13
+ }
14
+
15
+ function normalizeProgramGateFallbackChain(chainCandidate, dependencies = {}) {
16
+ const PROGRAM_GATE_PROFILE_POLICY = dependencies.PROGRAM_GATE_PROFILE_POLICY || {};
17
+ if (chainCandidate === undefined || chainCandidate === null) {
18
+ return null;
19
+ }
20
+ const raw = `${chainCandidate}`.trim();
21
+ if (!raw) {
22
+ return [];
23
+ }
24
+ const tokens = raw
25
+ .split(',')
26
+ .map(item => item.trim().toLowerCase())
27
+ .filter(Boolean);
28
+ if (tokens.length === 0) {
29
+ return [];
30
+ }
31
+ if (tokens.includes('none')) {
32
+ if (tokens.length > 1) {
33
+ throw new Error('--program-gate-fallback-chain cannot mix "none" with other profiles.');
34
+ }
35
+ return [];
36
+ }
37
+ const normalized = [];
38
+ const seen = new Set();
39
+ for (const token of tokens) {
40
+ if (!PROGRAM_GATE_PROFILE_POLICY[token]) {
41
+ throw new Error('--program-gate-fallback-chain must contain only: none, default, dev, staging, prod.');
42
+ }
43
+ if (seen.has(token)) {
44
+ continue;
45
+ }
46
+ seen.add(token);
47
+ normalized.push(token);
48
+ }
49
+ return normalized;
50
+ }
51
+
52
+ function resolveProgramGateFallbackChain(chainCandidate, fallbackProfileCandidate, dependencies = {}) {
53
+ const parsedChain = normalizeProgramGateFallbackChain(chainCandidate, dependencies);
54
+ if (Array.isArray(parsedChain)) {
55
+ return parsedChain;
56
+ }
57
+ const normalizedSingle = normalizeProgramGateFallbackProfile(fallbackProfileCandidate, dependencies);
58
+ return normalizedSingle === 'none' ? [] : [normalizedSingle];
59
+ }
60
+
61
+ function resolveProgramGatePolicy(policy = {}, dependencies = {}) {
62
+ const normalizeProgramGateProfile = dependencies.normalizeProgramGateProfile;
63
+ const normalizeProgramMinSuccessRate = dependencies.normalizeProgramMinSuccessRate;
64
+ const normalizeProgramRiskLevel = dependencies.normalizeProgramRiskLevel;
65
+ const normalizeProgramMaxElapsedMinutes = dependencies.normalizeProgramMaxElapsedMinutes;
66
+ const normalizeProgramMaxAgentBudget = dependencies.normalizeProgramMaxAgentBudget;
67
+ const normalizeProgramMaxTotalSubSpecs = dependencies.normalizeProgramMaxTotalSubSpecs;
68
+ const PROGRAM_GATE_PROFILE_POLICY = dependencies.PROGRAM_GATE_PROFILE_POLICY || {};
69
+
70
+ const profile = normalizeProgramGateProfile(policy.profile);
71
+ const profilePolicy = PROGRAM_GATE_PROFILE_POLICY[profile];
72
+ const minSuccessRate = policy.minSuccessRate === undefined || policy.minSuccessRate === null
73
+ ? normalizeProgramMinSuccessRate(profilePolicy.minSuccessRate)
74
+ : normalizeProgramMinSuccessRate(policy.minSuccessRate);
75
+ const maxRiskLevel = policy.maxRiskLevel === undefined || policy.maxRiskLevel === null
76
+ ? normalizeProgramRiskLevel(profilePolicy.maxRiskLevel)
77
+ : normalizeProgramRiskLevel(policy.maxRiskLevel);
78
+ const maxElapsedMinutes = policy.maxElapsedMinutes === undefined || policy.maxElapsedMinutes === null
79
+ ? normalizeProgramMaxElapsedMinutes(profilePolicy.maxElapsedMinutes)
80
+ : normalizeProgramMaxElapsedMinutes(policy.maxElapsedMinutes);
81
+ const maxAgentBudget = policy.maxAgentBudget === undefined || policy.maxAgentBudget === null
82
+ ? normalizeProgramMaxAgentBudget(profilePolicy.maxAgentBudget)
83
+ : normalizeProgramMaxAgentBudget(policy.maxAgentBudget);
84
+ const maxTotalSubSpecs = policy.maxTotalSubSpecs === undefined || policy.maxTotalSubSpecs === null
85
+ ? normalizeProgramMaxTotalSubSpecs(profilePolicy.maxTotalSubSpecs)
86
+ : normalizeProgramMaxTotalSubSpecs(policy.maxTotalSubSpecs);
87
+
88
+ return {
89
+ profile,
90
+ minSuccessRate,
91
+ maxRiskLevel,
92
+ maxElapsedMinutes,
93
+ maxAgentBudget,
94
+ maxTotalSubSpecs
95
+ };
96
+ }
97
+
98
+ function evaluateProgramConvergenceGate(summary, policy = {}, dependencies = {}) {
99
+ const buildProgramKpiSnapshot = dependencies.buildProgramKpiSnapshot;
100
+ const resolveProgramGatePolicyFn = dependencies.resolveProgramGatePolicy;
101
+
102
+ const metrics = summary && summary.metrics && typeof summary.metrics === 'object'
103
+ ? summary.metrics
104
+ : {};
105
+ const programKpi = summary && summary.program_kpi && typeof summary.program_kpi === 'object'
106
+ ? summary.program_kpi
107
+ : buildProgramKpiSnapshot(summary || {});
108
+ const resolvedPolicy = resolveProgramGatePolicyFn(policy);
109
+ const minSuccessRate = resolvedPolicy.minSuccessRate;
110
+ const maxRiskLevel = resolvedPolicy.maxRiskLevel;
111
+ const maxElapsedMinutes = resolvedPolicy.maxElapsedMinutes;
112
+ const maxAgentBudget = resolvedPolicy.maxAgentBudget;
113
+ const maxTotalSubSpecs = resolvedPolicy.maxTotalSubSpecs;
114
+ const completionRateFromKpi = Number(programKpi.completion_rate_percent);
115
+ const successRateFromMetrics = Number(metrics.success_rate_percent);
116
+ const successRate = Number.isFinite(completionRateFromKpi)
117
+ ? completionRateFromKpi
118
+ : (Number.isFinite(successRateFromMetrics) ? successRateFromMetrics : null);
119
+ const elapsedMsCandidate = Number(summary && summary.program_elapsed_ms);
120
+ const elapsedMs = Number.isFinite(elapsedMsCandidate) && elapsedMsCandidate >= 0
121
+ ? elapsedMsCandidate
122
+ : null;
123
+ const elapsedMinutes = elapsedMs === null
124
+ ? null
125
+ : Number((elapsedMs / 60000).toFixed(2));
126
+ const resourcePlan = summary && summary.resource_plan && typeof summary.resource_plan === 'object'
127
+ ? summary.resource_plan
128
+ : {};
129
+ const agentBudgetCandidate = Number(resourcePlan.agent_budget);
130
+ const effectiveParallelCandidate = Number(resourcePlan.effective_goal_parallel);
131
+ const batchParallelCandidate = Number(summary && summary.batch_parallel);
132
+ const actualAgentBudget = Number.isFinite(agentBudgetCandidate) && agentBudgetCandidate > 0
133
+ ? agentBudgetCandidate
134
+ : Number.isFinite(effectiveParallelCandidate) && effectiveParallelCandidate > 0
135
+ ? effectiveParallelCandidate
136
+ : Number.isFinite(batchParallelCandidate) && batchParallelCandidate > 0
137
+ ? batchParallelCandidate
138
+ : null;
139
+ const totalSubSpecsFromMetrics = Number(metrics.total_sub_specs);
140
+ const totalSubSpecs = Number.isFinite(totalSubSpecsFromMetrics)
141
+ ? totalSubSpecsFromMetrics
142
+ : (
143
+ Array.isArray(summary && summary.results)
144
+ ? summary.results.reduce((sum, item) => sum + (Number(item && item.sub_spec_count) || 0), 0)
145
+ : null
146
+ );
147
+ const riskLevel = `${programKpi.risk_level || 'high'}`.trim().toLowerCase();
148
+ const riskRank = { low: 1, medium: 2, high: 3 };
149
+ const reasons = [];
150
+ if (!Number.isFinite(successRate)) {
151
+ reasons.push('success_rate_percent unavailable');
152
+ } else if (successRate < minSuccessRate) {
153
+ reasons.push(`success_rate_percent ${successRate} < required ${minSuccessRate}`);
154
+ }
155
+ if ((riskRank[riskLevel] || 3) > (riskRank[maxRiskLevel] || 3)) {
156
+ reasons.push(`risk_level ${riskLevel} exceeds allowed ${maxRiskLevel}`);
157
+ }
158
+ if (maxElapsedMinutes !== null) {
159
+ if (!Number.isFinite(elapsedMinutes)) {
160
+ reasons.push('program_elapsed_minutes unavailable');
161
+ } else if (elapsedMinutes > maxElapsedMinutes) {
162
+ reasons.push(`program_elapsed_minutes ${elapsedMinutes} exceeds allowed ${maxElapsedMinutes}`);
163
+ }
164
+ }
165
+ if (maxAgentBudget !== null) {
166
+ if (!Number.isFinite(actualAgentBudget)) {
167
+ reasons.push('agent_budget unavailable');
168
+ } else if (actualAgentBudget > maxAgentBudget) {
169
+ reasons.push(`agent_budget ${actualAgentBudget} exceeds allowed ${maxAgentBudget}`);
170
+ }
171
+ }
172
+ if (maxTotalSubSpecs !== null) {
173
+ if (!Number.isFinite(totalSubSpecs)) {
174
+ reasons.push('total_sub_specs unavailable');
175
+ } else if (totalSubSpecs > maxTotalSubSpecs) {
176
+ reasons.push(`total_sub_specs ${totalSubSpecs} exceeds allowed ${maxTotalSubSpecs}`);
177
+ }
178
+ }
179
+
180
+ return {
181
+ passed: reasons.length === 0,
182
+ policy: {
183
+ profile: resolvedPolicy.profile,
184
+ min_success_rate_percent: minSuccessRate,
185
+ max_risk_level: maxRiskLevel,
186
+ max_elapsed_minutes: maxElapsedMinutes,
187
+ max_agent_budget: maxAgentBudget,
188
+ max_total_sub_specs: maxTotalSubSpecs
189
+ },
190
+ actual: {
191
+ success_rate_percent: Number.isFinite(successRate) ? successRate : null,
192
+ risk_level: riskLevel,
193
+ elapsed_minutes: Number.isFinite(elapsedMinutes) ? elapsedMinutes : null,
194
+ agent_budget: Number.isFinite(actualAgentBudget) ? actualAgentBudget : null,
195
+ total_sub_specs: Number.isFinite(totalSubSpecs) ? totalSubSpecs : null
196
+ },
197
+ reasons
198
+ };
199
+ }
200
+
201
+ function applyAnomalyBatchConcurrencyReductionPatch(summary, patch, reasons, options, anomalyType, dependencies = {}) {
202
+ const normalizeBatchParallel = dependencies.normalizeBatchParallel;
203
+ const normalizeBatchAgentBudget = dependencies.normalizeBatchAgentBudget;
204
+
205
+ const currentParallelCandidate = patch.batchParallel !== undefined && patch.batchParallel !== null
206
+ ? patch.batchParallel
207
+ : (
208
+ options.batchParallel !== undefined && options.batchParallel !== null
209
+ ? options.batchParallel
210
+ : (summary && summary.batch_parallel ? summary.batch_parallel : 1)
211
+ );
212
+ const currentParallel = normalizeBatchParallel(currentParallelCandidate);
213
+ if (currentParallel > 1) {
214
+ patch.batchParallel = currentParallel - 1;
215
+ reasons.push(`reduce batch parallel from ${currentParallel} to ${patch.batchParallel} due to ${anomalyType}`);
216
+ }
217
+
218
+ const currentAgentBudgetCandidate = patch.batchAgentBudget !== undefined && patch.batchAgentBudget !== null
219
+ ? patch.batchAgentBudget
220
+ : (
221
+ options.batchAgentBudget !== undefined && options.batchAgentBudget !== null
222
+ ? options.batchAgentBudget
223
+ : (summary && summary.resource_plan ? summary.resource_plan.agent_budget : null)
224
+ );
225
+ const currentAgentBudget = normalizeBatchAgentBudget(currentAgentBudgetCandidate);
226
+ if (currentAgentBudget !== null && currentAgentBudget > 1) {
227
+ patch.batchAgentBudget = currentAgentBudget - 1;
228
+ reasons.push(`reduce batch agent budget from ${currentAgentBudget} to ${patch.batchAgentBudget} due to ${anomalyType}`);
229
+ }
230
+ }
231
+
232
+ function buildProgramAnomalyGovernancePatch(summary, anomalies, options = {}, dependencies = {}) {
233
+ const normalizeBatchRetryRounds = dependencies.normalizeBatchRetryRounds;
234
+ const normalizeBatchParallel = dependencies.normalizeBatchParallel;
235
+ const normalizeBatchAgentBudget = dependencies.normalizeBatchAgentBudget;
236
+
237
+ const sourceAnomalies = Array.isArray(anomalies) ? anomalies : [];
238
+ const highAnomalies = sourceAnomalies.filter(item => `${item && item.severity ? item.severity : ''}`.trim().toLowerCase() === 'high');
239
+ const patch = {};
240
+ const reasons = [];
241
+
242
+ const anomalyTypes = new Set(highAnomalies.map(item => `${item && item.type ? item.type : ''}`.trim().toLowerCase()));
243
+ if (anomalyTypes.has('success-rate-drop')) {
244
+ const currentRetryRounds = normalizeBatchRetryRounds(options.batchRetryRounds);
245
+ patch.batchRetryRounds = Math.min(5, Math.max(1, currentRetryRounds + 1));
246
+ patch.batchRetryUntilComplete = true;
247
+ reasons.push('increase retry rounds due to success-rate-drop anomaly');
248
+ }
249
+
250
+ if (anomalyTypes.has('failed-goals-spike')) {
251
+ applyAnomalyBatchConcurrencyReductionPatch(summary, patch, reasons, options, 'failed-goals-spike', {
252
+ normalizeBatchParallel,
253
+ normalizeBatchAgentBudget
254
+ });
255
+ }
256
+
257
+ if (anomalyTypes.has('rate-limit-spike')) {
258
+ applyAnomalyBatchConcurrencyReductionPatch(summary, patch, reasons, options, 'rate-limit-spike', {
259
+ normalizeBatchParallel,
260
+ normalizeBatchAgentBudget
261
+ });
262
+ }
263
+
264
+ if (anomalyTypes.has('spec-growth-spike')) {
265
+ patch.specSessionBudgetHardFail = true;
266
+ reasons.push('enable spec-session budget hard-fail due to spec-growth-spike');
267
+ if (options.specSessionMaxCreated === undefined || options.specSessionMaxCreated === null) {
268
+ const estimatedCreated = Number(summary && summary.spec_session_budget && summary.spec_session_budget.estimated_created) || 0;
269
+ patch.specSessionMaxCreated = Math.max(1, Math.ceil(estimatedCreated * 0.8));
270
+ reasons.push(`set specSessionMaxCreated=${patch.specSessionMaxCreated} due to spec-growth-spike`);
271
+ }
272
+ }
273
+
274
+ return {
275
+ patch,
276
+ reasons,
277
+ anomaly_count: highAnomalies.length,
278
+ anomaly_types: [...anomalyTypes]
279
+ };
280
+ }
281
+
282
+ function normalizeFailureSignatureFromError(errorMessage) {
283
+ if (typeof errorMessage !== 'string' || !errorMessage.trim()) {
284
+ return 'no-error-details';
285
+ }
286
+
287
+ return errorMessage
288
+ .toLowerCase()
289
+ .replace(/[0-9]+/g, '#')
290
+ .replace(/[a-z]:\\[^ ]+/gi, '<path>')
291
+ .replace(/\/[^ ]+/g, '<path>')
292
+ .replace(/["'`]/g, '')
293
+ .replace(/\s+/g, ' ')
294
+ .trim()
295
+ .slice(0, 120);
296
+ }
297
+
298
+ module.exports = {
299
+ normalizeProgramGateFallbackProfile,
300
+ normalizeProgramGateFallbackChain,
301
+ resolveProgramGateFallbackChain,
302
+ resolveProgramGatePolicy,
303
+ evaluateProgramConvergenceGate,
304
+ buildProgramAnomalyGovernancePatch,
305
+ normalizeFailureSignatureFromError
306
+ };