scene-capability-engine 3.6.45 → 3.6.46

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 (56) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/docs/releases/README.md +1 -0
  3. package/docs/releases/v3.6.46.md +23 -0
  4. package/docs/zh/releases/README.md +1 -0
  5. package/docs/zh/releases/v3.6.46.md +23 -0
  6. package/package.json +4 -2
  7. package/scripts/auto-strategy-router.js +231 -0
  8. package/scripts/capability-mapping-report.js +339 -0
  9. package/scripts/check-branding-consistency.js +140 -0
  10. package/scripts/check-sce-tracking.js +54 -0
  11. package/scripts/check-skip-allowlist.js +94 -0
  12. package/scripts/errorbook-registry-health-gate.js +172 -0
  13. package/scripts/errorbook-release-gate.js +132 -0
  14. package/scripts/failure-attribution-repair.js +317 -0
  15. package/scripts/git-managed-gate.js +464 -0
  16. package/scripts/interactive-approval-event-projection.js +400 -0
  17. package/scripts/interactive-approval-workflow.js +829 -0
  18. package/scripts/interactive-authorization-tier-evaluate.js +413 -0
  19. package/scripts/interactive-change-plan-gate.js +225 -0
  20. package/scripts/interactive-context-bridge.js +617 -0
  21. package/scripts/interactive-customization-loop.js +1690 -0
  22. package/scripts/interactive-dialogue-governance.js +842 -0
  23. package/scripts/interactive-feedback-log.js +253 -0
  24. package/scripts/interactive-flow-smoke.js +238 -0
  25. package/scripts/interactive-flow.js +1059 -0
  26. package/scripts/interactive-governance-report.js +1112 -0
  27. package/scripts/interactive-intent-build.js +707 -0
  28. package/scripts/interactive-loop-smoke.js +215 -0
  29. package/scripts/interactive-moqui-adapter.js +304 -0
  30. package/scripts/interactive-plan-build.js +426 -0
  31. package/scripts/interactive-runtime-policy-evaluate.js +495 -0
  32. package/scripts/interactive-work-order-build.js +552 -0
  33. package/scripts/matrix-regression-gate.js +167 -0
  34. package/scripts/moqui-core-regression-suite.js +397 -0
  35. package/scripts/moqui-lexicon-audit.js +651 -0
  36. package/scripts/moqui-matrix-remediation-phased-runner.js +865 -0
  37. package/scripts/moqui-matrix-remediation-queue.js +852 -0
  38. package/scripts/moqui-metadata-extract.js +1340 -0
  39. package/scripts/moqui-rebuild-gate.js +167 -0
  40. package/scripts/moqui-release-summary.js +729 -0
  41. package/scripts/moqui-standard-rebuild.js +1370 -0
  42. package/scripts/moqui-template-baseline-report.js +682 -0
  43. package/scripts/npm-package-runtime-asset-check.js +221 -0
  44. package/scripts/problem-closure-gate.js +441 -0
  45. package/scripts/release-asset-integrity-check.js +216 -0
  46. package/scripts/release-asset-nonempty-normalize.js +166 -0
  47. package/scripts/release-drift-evaluate.js +223 -0
  48. package/scripts/release-drift-signals.js +255 -0
  49. package/scripts/release-governance-snapshot-export.js +132 -0
  50. package/scripts/release-ops-weekly-summary.js +934 -0
  51. package/scripts/release-risk-remediation-bundle.js +315 -0
  52. package/scripts/release-weekly-ops-gate.js +423 -0
  53. package/scripts/state-migration-reconciliation-gate.js +110 -0
  54. package/scripts/state-storage-tiering-audit.js +337 -0
  55. package/scripts/steering-content-audit.js +393 -0
  56. package/scripts/symbol-evidence-locate.js +366 -0
@@ -0,0 +1,393 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const yaml = require('js-yaml');
7
+
8
+ const DEFAULT_GOVERNANCE = {
9
+ review_cadence: 'weekly',
10
+ stable_layers: [
11
+ 'CORE_PRINCIPLES.md',
12
+ 'ENVIRONMENT.md',
13
+ 'RULES_GUIDE.md'
14
+ ],
15
+ files: {
16
+ 'CORE_PRINCIPLES.md': {
17
+ max_lines: 96,
18
+ max_headings: 16,
19
+ max_history_entries: 0,
20
+ allow_spec_refs: false,
21
+ allow_version_markers: false,
22
+ allow_checklists: false
23
+ },
24
+ 'ENVIRONMENT.md': {
25
+ max_lines: 36,
26
+ max_headings: 8,
27
+ max_history_entries: 0,
28
+ allow_spec_refs: false,
29
+ allow_version_markers: false,
30
+ allow_checklists: false
31
+ },
32
+ 'CURRENT_CONTEXT.md': {
33
+ max_lines: 24,
34
+ max_headings: 6,
35
+ max_history_entries: 3,
36
+ allow_spec_refs: true,
37
+ allow_version_markers: true,
38
+ allow_checklists: false
39
+ },
40
+ 'RULES_GUIDE.md': {
41
+ max_lines: 36,
42
+ max_headings: 8,
43
+ max_history_entries: 0,
44
+ allow_spec_refs: false,
45
+ allow_version_markers: false,
46
+ allow_checklists: false
47
+ }
48
+ },
49
+ canonical_terms: {
50
+ errorbook: {
51
+ aliases: ['错题', '错题本'],
52
+ guidance: 'Reuse the existing errorbook capability instead of inventing a parallel mistake-book mode in steering.'
53
+ }
54
+ },
55
+ relocation_targets: {
56
+ long_lived_principles: '.sce/steering/CORE_PRINCIPLES.md',
57
+ project_operating_rules: '.sce/steering/ENVIRONMENT.md',
58
+ active_delivery_context: '.sce/steering/CURRENT_CONTEXT.md',
59
+ detailed_workflow_and_examples: 'docs/steering-governance.md',
60
+ transient_task_state: '.sce/specs/<spec>/tasks.md',
61
+ historical_decisions_and_evidence: '.sce/specs/<spec>/custom/'
62
+ }
63
+ };
64
+
65
+ function parseArgs(argv = process.argv.slice(2)) {
66
+ const options = {
67
+ projectPath: process.cwd(),
68
+ json: false,
69
+ failOnError: false,
70
+ failOnWarning: false,
71
+ out: null
72
+ };
73
+
74
+ for (let index = 0; index < argv.length; index += 1) {
75
+ const value = argv[index];
76
+ if (value === '--json') {
77
+ options.json = true;
78
+ continue;
79
+ }
80
+ if (value === '--fail-on-error') {
81
+ options.failOnError = true;
82
+ continue;
83
+ }
84
+ if (value === '--fail-on-warning') {
85
+ options.failOnWarning = true;
86
+ continue;
87
+ }
88
+ if (value === '--project-path') {
89
+ options.projectPath = path.resolve(argv[index + 1] || process.cwd());
90
+ index += 1;
91
+ continue;
92
+ }
93
+ if (value === '--out') {
94
+ options.out = path.resolve(argv[index + 1] || '');
95
+ index += 1;
96
+ continue;
97
+ }
98
+ }
99
+
100
+ return options;
101
+ }
102
+
103
+ function mergeGovernance(manifestGovernance = {}) {
104
+ const mergedFiles = { ...DEFAULT_GOVERNANCE.files };
105
+ const manifestFiles = manifestGovernance.files || {};
106
+ for (const [name, config] of Object.entries(manifestFiles)) {
107
+ mergedFiles[name] = {
108
+ ...(mergedFiles[name] || {}),
109
+ ...(config || {})
110
+ };
111
+ }
112
+
113
+ return {
114
+ ...DEFAULT_GOVERNANCE,
115
+ ...manifestGovernance,
116
+ stable_layers: Array.isArray(manifestGovernance.stable_layers)
117
+ ? manifestGovernance.stable_layers.slice()
118
+ : DEFAULT_GOVERNANCE.stable_layers.slice(),
119
+ canonical_terms: {
120
+ ...DEFAULT_GOVERNANCE.canonical_terms,
121
+ ...(manifestGovernance.canonical_terms || {})
122
+ },
123
+ relocation_targets: {
124
+ ...DEFAULT_GOVERNANCE.relocation_targets,
125
+ ...(manifestGovernance.relocation_targets || {})
126
+ },
127
+ files: mergedFiles
128
+ };
129
+ }
130
+
131
+ function loadSteeringManifest(projectPath) {
132
+ const steeringDir = path.join(projectPath, '.sce', 'steering');
133
+ const manifestPath = path.join(steeringDir, 'manifest.yaml');
134
+ let manifest = {};
135
+
136
+ if (fs.existsSync(manifestPath)) {
137
+ manifest = yaml.load(fs.readFileSync(manifestPath, 'utf8')) || {};
138
+ }
139
+
140
+ const governance = mergeGovernance(manifest.governance || {});
141
+ const layers = manifest.layers || {
142
+ core_principles: 'CORE_PRINCIPLES.md',
143
+ environment: 'ENVIRONMENT.md',
144
+ current_context: 'CURRENT_CONTEXT.md',
145
+ rules_guide: 'RULES_GUIDE.md'
146
+ };
147
+
148
+ return {
149
+ steeringDir,
150
+ manifestPath,
151
+ manifest,
152
+ governance,
153
+ layers
154
+ };
155
+ }
156
+
157
+ function countMatches(text, regex) {
158
+ const matches = text.match(regex);
159
+ return matches ? matches.length : 0;
160
+ }
161
+
162
+ function collectMetrics(fileName, content) {
163
+ const lines = content.split(/\r?\n/);
164
+ const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
165
+
166
+ return {
167
+ file: fileName,
168
+ lines: lines.length,
169
+ words: content.trim().length === 0 ? 0 : content.trim().split(/\s+/).filter(Boolean).length,
170
+ headings: countMatches(content, /^#{1,6}\s+/gm),
171
+ historyEntries: countMatches(content, /^v\d+\.\d+(?:\.\d+)?\s+\|/gm),
172
+ checklistItems: countMatches(content, /^\s*[-*]\s+\[[ xX]\]/gm),
173
+ specRefs: countMatches(content, /\bSpec\s+\d+\b|\b\d{2,3}-\d{2}-[a-z0-9-]+\b/gi),
174
+ versionMarkers: countMatches(content, /\bv\d+\.\d+(?:\.\d+)?\b/g),
175
+ nonEmptyLines: nonEmptyLines.length
176
+ };
177
+ }
178
+
179
+ function pushViolation(violations, severity, file, rule, message, suggestion) {
180
+ violations.push({
181
+ severity,
182
+ file,
183
+ rule,
184
+ message,
185
+ suggestion
186
+ });
187
+ }
188
+
189
+ function auditSteeringContent(options = {}) {
190
+ const projectPath = path.resolve(options.projectPath || process.cwd());
191
+ const packageJsonPath = path.join(projectPath, 'package.json');
192
+ const packageVersion = fs.existsSync(packageJsonPath)
193
+ ? JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')).version
194
+ : null;
195
+ const loaded = loadSteeringManifest(projectPath);
196
+ const {
197
+ steeringDir,
198
+ governance,
199
+ layers
200
+ } = loaded;
201
+
202
+ const fileNames = Array.from(new Set(Object.values(layers)));
203
+ const files = [];
204
+ const violations = [];
205
+
206
+ for (const fileName of fileNames) {
207
+ const absolutePath = path.join(steeringDir, fileName);
208
+ if (!fs.existsSync(absolutePath)) {
209
+ pushViolation(
210
+ violations,
211
+ 'error',
212
+ fileName,
213
+ 'missing_file',
214
+ `Missing steering layer file: ${fileName}`,
215
+ `Restore ${fileName} under ${steeringDir}.`
216
+ );
217
+ continue;
218
+ }
219
+
220
+ const content = fs.readFileSync(absolutePath, 'utf8');
221
+ const metrics = collectMetrics(fileName, content);
222
+ const config = governance.files[fileName] || {};
223
+ files.push({
224
+ file: fileName,
225
+ path: absolutePath,
226
+ metrics,
227
+ config
228
+ });
229
+
230
+ if (typeof config.max_lines === 'number' && metrics.lines > config.max_lines) {
231
+ pushViolation(
232
+ violations,
233
+ 'error',
234
+ fileName,
235
+ 'line_budget_exceeded',
236
+ `${fileName} has ${metrics.lines} lines, above the ${config.max_lines}-line budget.`,
237
+ `Move detailed procedures or historical detail to ${governance.relocation_targets.detailed_workflow_and_examples} or a Spec archive.`
238
+ );
239
+ }
240
+
241
+ if (typeof config.max_headings === 'number' && metrics.headings > config.max_headings) {
242
+ pushViolation(
243
+ violations,
244
+ 'warning',
245
+ fileName,
246
+ 'heading_budget_exceeded',
247
+ `${fileName} has ${metrics.headings} headings, above the ${config.max_headings}-heading budget.`,
248
+ 'Merge related sections and keep only durable decisions in steering.'
249
+ );
250
+ }
251
+
252
+ if (typeof config.max_history_entries === 'number' && metrics.historyEntries > config.max_history_entries) {
253
+ pushViolation(
254
+ violations,
255
+ 'error',
256
+ fileName,
257
+ 'history_budget_exceeded',
258
+ `${fileName} contains ${metrics.historyEntries} historical version entries, above the ${config.max_history_entries}-entry budget.`,
259
+ `Archive historical progress into ${governance.relocation_targets.historical_decisions_and_evidence}.`
260
+ );
261
+ }
262
+
263
+ if (config.allow_checklists === false && metrics.checklistItems > 0) {
264
+ pushViolation(
265
+ violations,
266
+ 'error',
267
+ fileName,
268
+ 'task_checklist_in_steering',
269
+ `${fileName} contains ${metrics.checklistItems} checklist item(s).`,
270
+ `Move executable task state into ${governance.relocation_targets.transient_task_state}.`
271
+ );
272
+ }
273
+
274
+ if (config.allow_spec_refs === false && metrics.specRefs > 0) {
275
+ pushViolation(
276
+ violations,
277
+ 'warning',
278
+ fileName,
279
+ 'spec_reference_in_stable_layer',
280
+ `${fileName} contains ${metrics.specRefs} Spec or spec-id reference(s).`,
281
+ `Move volatile delivery detail into ${governance.relocation_targets.active_delivery_context} or a Spec archive.`
282
+ );
283
+ }
284
+
285
+ if (config.allow_version_markers === false && metrics.versionMarkers > 0) {
286
+ pushViolation(
287
+ violations,
288
+ 'warning',
289
+ fileName,
290
+ 'version_marker_in_stable_layer',
291
+ `${fileName} contains ${metrics.versionMarkers} version marker(s).`,
292
+ 'Remove release-history footers from stable steering layers; keep version tracking in CHANGELOG or release notes.'
293
+ );
294
+ }
295
+
296
+ if (fileName === 'CURRENT_CONTEXT.md' && packageVersion) {
297
+ const versionMatch = content.match(/\*\*版本\*\*:\s*`([^`]+)`/);
298
+ if (versionMatch && versionMatch[1].trim() !== packageVersion) {
299
+ pushViolation(
300
+ violations,
301
+ 'warning',
302
+ fileName,
303
+ 'stale_context_version',
304
+ `CURRENT_CONTEXT.md tracks version ${versionMatch[1].trim()} but package.json is ${packageVersion}.`,
305
+ 'Refresh CURRENT_CONTEXT.md after version bumps or release completion.'
306
+ );
307
+ }
308
+ }
309
+
310
+ for (const [canonicalName, definition] of Object.entries(governance.canonical_terms || {})) {
311
+ const aliases = Array.isArray(definition.aliases) ? definition.aliases : [];
312
+ for (const alias of aliases) {
313
+ const escaped = `${alias}`.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
314
+ const aliasCount = countMatches(content, new RegExp(escaped, 'g'));
315
+ if (aliasCount > 0) {
316
+ pushViolation(
317
+ violations,
318
+ 'warning',
319
+ fileName,
320
+ 'non_canonical_mechanism_alias',
321
+ `${fileName} uses non-canonical mechanism alias "${alias}" (${aliasCount} occurrence(s)); canonical term is "${canonicalName}".`,
322
+ definition.guidance || `Use the canonical term "${canonicalName}" and reference the existing SCE capability.`
323
+ );
324
+ }
325
+ }
326
+ }
327
+ }
328
+
329
+ const errorCount = violations.filter((item) => item.severity === 'error').length;
330
+ const warningCount = violations.filter((item) => item.severity === 'warning').length;
331
+
332
+ return {
333
+ mode: 'steering-content-audit',
334
+ passed: errorCount === 0,
335
+ project_path: projectPath,
336
+ steering_path: steeringDir,
337
+ review_cadence: governance.review_cadence,
338
+ error_count: errorCount,
339
+ warning_count: warningCount,
340
+ files: files.map((entry) => ({
341
+ file: entry.file,
342
+ metrics: entry.metrics,
343
+ config: entry.config
344
+ })),
345
+ violations
346
+ };
347
+ }
348
+
349
+ function printHumanReport(result) {
350
+ if (result.violations.length === 0) {
351
+ console.log('Steering content audit passed: steering layers are within hygiene budgets.');
352
+ return;
353
+ }
354
+
355
+ console.error(`Steering content audit found ${result.error_count} error(s) and ${result.warning_count} warning(s).`);
356
+ for (const violation of result.violations) {
357
+ console.error(`- [${violation.severity}] ${violation.file} / ${violation.rule}: ${violation.message}`);
358
+ if (violation.suggestion) {
359
+ console.error(` suggestion: ${violation.suggestion}`);
360
+ }
361
+ }
362
+ }
363
+
364
+ function maybeWriteReport(outputPath, result) {
365
+ if (!outputPath) {
366
+ return;
367
+ }
368
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
369
+ fs.writeFileSync(outputPath, `${JSON.stringify(result, null, 2)}\n`, 'utf8');
370
+ }
371
+
372
+ if (require.main === module) {
373
+ const options = parseArgs(process.argv.slice(2));
374
+ const result = auditSteeringContent(options);
375
+ maybeWriteReport(options.out, result);
376
+
377
+ if (options.json) {
378
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
379
+ } else {
380
+ printHumanReport(result);
381
+ }
382
+
383
+ if ((options.failOnWarning && result.warning_count > 0) || (options.failOnError && result.error_count > 0)) {
384
+ process.exit(1);
385
+ }
386
+ }
387
+
388
+ module.exports = {
389
+ DEFAULT_GOVERNANCE,
390
+ auditSteeringContent,
391
+ loadSteeringManifest,
392
+ parseArgs
393
+ };