scene-capability-engine 3.6.44 → 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 (61) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/bin/scene-capability-engine.js +36 -2
  3. package/docs/command-reference.md +5 -0
  4. package/docs/releases/README.md +2 -0
  5. package/docs/releases/v3.6.45.md +18 -0
  6. package/docs/releases/v3.6.46.md +23 -0
  7. package/docs/zh/releases/README.md +2 -0
  8. package/docs/zh/releases/v3.6.45.md +18 -0
  9. package/docs/zh/releases/v3.6.46.md +23 -0
  10. package/lib/workspace/collab-governance-audit.js +575 -0
  11. package/package.json +4 -2
  12. package/scripts/auto-strategy-router.js +231 -0
  13. package/scripts/capability-mapping-report.js +339 -0
  14. package/scripts/check-branding-consistency.js +140 -0
  15. package/scripts/check-sce-tracking.js +54 -0
  16. package/scripts/check-skip-allowlist.js +94 -0
  17. package/scripts/errorbook-registry-health-gate.js +172 -0
  18. package/scripts/errorbook-release-gate.js +132 -0
  19. package/scripts/failure-attribution-repair.js +317 -0
  20. package/scripts/git-managed-gate.js +464 -0
  21. package/scripts/interactive-approval-event-projection.js +400 -0
  22. package/scripts/interactive-approval-workflow.js +829 -0
  23. package/scripts/interactive-authorization-tier-evaluate.js +413 -0
  24. package/scripts/interactive-change-plan-gate.js +225 -0
  25. package/scripts/interactive-context-bridge.js +617 -0
  26. package/scripts/interactive-customization-loop.js +1690 -0
  27. package/scripts/interactive-dialogue-governance.js +842 -0
  28. package/scripts/interactive-feedback-log.js +253 -0
  29. package/scripts/interactive-flow-smoke.js +238 -0
  30. package/scripts/interactive-flow.js +1059 -0
  31. package/scripts/interactive-governance-report.js +1112 -0
  32. package/scripts/interactive-intent-build.js +707 -0
  33. package/scripts/interactive-loop-smoke.js +215 -0
  34. package/scripts/interactive-moqui-adapter.js +304 -0
  35. package/scripts/interactive-plan-build.js +426 -0
  36. package/scripts/interactive-runtime-policy-evaluate.js +495 -0
  37. package/scripts/interactive-work-order-build.js +552 -0
  38. package/scripts/matrix-regression-gate.js +167 -0
  39. package/scripts/moqui-core-regression-suite.js +397 -0
  40. package/scripts/moqui-lexicon-audit.js +651 -0
  41. package/scripts/moqui-matrix-remediation-phased-runner.js +865 -0
  42. package/scripts/moqui-matrix-remediation-queue.js +852 -0
  43. package/scripts/moqui-metadata-extract.js +1340 -0
  44. package/scripts/moqui-rebuild-gate.js +167 -0
  45. package/scripts/moqui-release-summary.js +729 -0
  46. package/scripts/moqui-standard-rebuild.js +1370 -0
  47. package/scripts/moqui-template-baseline-report.js +682 -0
  48. package/scripts/npm-package-runtime-asset-check.js +221 -0
  49. package/scripts/problem-closure-gate.js +441 -0
  50. package/scripts/release-asset-integrity-check.js +216 -0
  51. package/scripts/release-asset-nonempty-normalize.js +166 -0
  52. package/scripts/release-drift-evaluate.js +223 -0
  53. package/scripts/release-drift-signals.js +255 -0
  54. package/scripts/release-governance-snapshot-export.js +132 -0
  55. package/scripts/release-ops-weekly-summary.js +934 -0
  56. package/scripts/release-risk-remediation-bundle.js +315 -0
  57. package/scripts/release-weekly-ops-gate.js +423 -0
  58. package/scripts/state-migration-reconciliation-gate.js +110 -0
  59. package/scripts/state-storage-tiering-audit.js +337 -0
  60. package/scripts/steering-content-audit.js +393 -0
  61. package/scripts/symbol-evidence-locate.js +366 -0
@@ -0,0 +1,337 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const { minimatch } = require('minimatch');
7
+ const {
8
+ cloneStateStoragePolicyDefaults,
9
+ REQUIRED_COMPONENT_IDS
10
+ } = require('../lib/state/state-storage-policy');
11
+
12
+ function parseArgs(argv = []) {
13
+ const options = {
14
+ projectPath: process.cwd(),
15
+ policyPath: null,
16
+ json: false,
17
+ failOnWarning: false,
18
+ out: null
19
+ };
20
+
21
+ for (let index = 0; index < argv.length; index += 1) {
22
+ const token = argv[index];
23
+ const next = argv[index + 1];
24
+ if (token === '--project-path' || token === '--workspace') {
25
+ if (next) {
26
+ options.projectPath = path.resolve(next);
27
+ index += 1;
28
+ }
29
+ continue;
30
+ }
31
+ if (token === '--policy') {
32
+ if (next) {
33
+ options.policyPath = path.resolve(options.projectPath, next);
34
+ index += 1;
35
+ }
36
+ continue;
37
+ }
38
+ if (token === '--json') {
39
+ options.json = true;
40
+ continue;
41
+ }
42
+ if (token === '--fail-on-warning') {
43
+ options.failOnWarning = true;
44
+ continue;
45
+ }
46
+ if (token === '--out') {
47
+ if (next) {
48
+ options.out = path.resolve(next);
49
+ index += 1;
50
+ }
51
+ }
52
+ }
53
+
54
+ return options;
55
+ }
56
+
57
+ function pushViolation(violations, severity, rule, message, details = {}) {
58
+ violations.push({
59
+ severity,
60
+ rule,
61
+ message,
62
+ ...details
63
+ });
64
+ }
65
+
66
+ function collectFilesRecursive(rootDir, relativePrefix = '') {
67
+ if (!fs.existsSync(rootDir)) {
68
+ return [];
69
+ }
70
+ const entries = fs.readdirSync(rootDir, { withFileTypes: true });
71
+ const results = [];
72
+ for (const entry of entries) {
73
+ const absolutePath = path.join(rootDir, entry.name);
74
+ const relativePath = path.posix.join(relativePrefix, entry.name);
75
+ if (entry.isDirectory()) {
76
+ results.push(...collectFilesRecursive(absolutePath, relativePath));
77
+ } else {
78
+ results.push(relativePath);
79
+ }
80
+ }
81
+ return results;
82
+ }
83
+
84
+ function normalizeRulePatterns(rule = {}) {
85
+ return []
86
+ .concat(Array.isArray(rule.path_patterns) ? rule.path_patterns : [])
87
+ .concat(Array.isArray(rule.explicit_paths) ? rule.explicit_paths : []);
88
+ }
89
+
90
+ function loadPolicy(projectPath, explicitPolicyPath = null) {
91
+ const defaultPath = path.join(projectPath, '.sce', 'config', 'state-storage-policy.json');
92
+ const policyPath = explicitPolicyPath || defaultPath;
93
+ if (!fs.existsSync(policyPath)) {
94
+ return {
95
+ policyPath,
96
+ exists: false,
97
+ policy: cloneStateStoragePolicyDefaults()
98
+ };
99
+ }
100
+ return {
101
+ policyPath,
102
+ exists: true,
103
+ policy: JSON.parse(fs.readFileSync(policyPath, 'utf8'))
104
+ };
105
+ }
106
+
107
+ function auditStateStorageTiering(options = {}) {
108
+ const projectPath = path.resolve(options.projectPath || process.cwd());
109
+ const loaded = loadPolicy(projectPath, options.policyPath || null);
110
+ const policy = loaded.policy || {};
111
+ const violations = [];
112
+
113
+ if (!loaded.exists) {
114
+ pushViolation(
115
+ violations,
116
+ 'error',
117
+ 'missing_policy_file',
118
+ 'State storage policy file is missing.',
119
+ { path: path.relative(projectPath, loaded.policyPath).replace(/\\/g, '/') || loaded.policyPath }
120
+ );
121
+ }
122
+
123
+ if (policy.schema_version !== '1.0') {
124
+ pushViolation(violations, 'error', 'invalid_schema_version', 'State storage policy must declare schema_version 1.0.');
125
+ }
126
+
127
+ if (policy.strategy !== 'selective-sqlite-advancement') {
128
+ pushViolation(
129
+ violations,
130
+ 'error',
131
+ 'invalid_strategy',
132
+ 'State storage policy must use the selective-sqlite-advancement strategy.'
133
+ );
134
+ }
135
+
136
+ const componentScope = Array.isArray(policy.component_scope) ? policy.component_scope : [];
137
+ const componentIds = new Set(componentScope.map((item) => `${item && item.component_id ? item.component_id : ''}`.trim()).filter(Boolean));
138
+ for (const id of REQUIRED_COMPONENT_IDS) {
139
+ if (!componentIds.has(id)) {
140
+ pushViolation(
141
+ violations,
142
+ 'error',
143
+ 'missing_component_scope',
144
+ `Missing required component scope entry for ${id}.`,
145
+ { component_id: id }
146
+ );
147
+ }
148
+ }
149
+
150
+ for (const component of componentScope) {
151
+ if (!component || !component.component_id) {
152
+ pushViolation(violations, 'error', 'invalid_component_scope_entry', 'Component scope entries must declare component_id.');
153
+ continue;
154
+ }
155
+ if (component.tier !== 'sqlite-index') {
156
+ pushViolation(
157
+ violations,
158
+ 'error',
159
+ 'invalid_component_tier',
160
+ `${component.component_id} must remain classified as sqlite-index.`,
161
+ { component_id: component.component_id }
162
+ );
163
+ }
164
+ if (component.canonical_source !== 'file') {
165
+ pushViolation(
166
+ violations,
167
+ 'warning',
168
+ 'non_file_canonical_source',
169
+ `${component.component_id} should declare file as canonical_source for the current gradual migration model.`,
170
+ { component_id: component.component_id }
171
+ );
172
+ }
173
+ if (!component.source_path) {
174
+ pushViolation(
175
+ violations,
176
+ 'error',
177
+ 'missing_component_source_path',
178
+ `${component.component_id} must declare source_path.`,
179
+ { component_id: component.component_id }
180
+ );
181
+ }
182
+ }
183
+
184
+ const resourceRules = Array.isArray(policy.resource_rules) ? policy.resource_rules : [];
185
+ const workspaceRule = resourceRules.find((rule) => Array.isArray(rule.explicit_paths) && rule.explicit_paths.includes('~/.sce/workspace-state.json'));
186
+ if (!workspaceRule) {
187
+ pushViolation(
188
+ violations,
189
+ 'error',
190
+ 'missing_workspace_state_rule',
191
+ 'Policy must explicitly classify ~/.sce/workspace-state.json.'
192
+ );
193
+ } else {
194
+ if (workspaceRule.tier !== 'file-source') {
195
+ pushViolation(
196
+ violations,
197
+ 'error',
198
+ 'workspace_state_wrong_tier',
199
+ 'Workspace personal state must remain file-source.'
200
+ );
201
+ }
202
+ if (workspaceRule.source_replacement_allowed !== false) {
203
+ pushViolation(
204
+ violations,
205
+ 'error',
206
+ 'workspace_state_source_replacement',
207
+ 'Workspace personal state must not allow SQLite source replacement.'
208
+ );
209
+ }
210
+ }
211
+
212
+ const appendOnlyRuleIds = new Set();
213
+ for (const rule of resourceRules) {
214
+ const patterns = normalizeRulePatterns(rule);
215
+ if (patterns.some((pattern) => pattern === '.sce/reports/**/*.jsonl' || pattern === '.sce/audit/**/*.jsonl')) {
216
+ appendOnlyRuleIds.add(rule.rule_id);
217
+ if (rule.tier !== 'file-source') {
218
+ pushViolation(
219
+ violations,
220
+ 'error',
221
+ 'append_only_wrong_tier',
222
+ `${rule.rule_id} must remain file-source.`,
223
+ { rule_id: rule.rule_id }
224
+ );
225
+ }
226
+ if (rule.source_replacement_allowed !== false) {
227
+ pushViolation(
228
+ violations,
229
+ 'error',
230
+ 'append_only_source_replacement',
231
+ `${rule.rule_id} must not allow SQLite source replacement.`,
232
+ { rule_id: rule.rule_id }
233
+ );
234
+ }
235
+ }
236
+ }
237
+
238
+ if (!appendOnlyRuleIds.has('append-only-report-streams')) {
239
+ pushViolation(
240
+ violations,
241
+ 'error',
242
+ 'missing_append_only_report_rule',
243
+ 'Policy must explicitly protect .sce/reports/**/*.jsonl as file-source.'
244
+ );
245
+ }
246
+ if (!appendOnlyRuleIds.has('append-only-audit-streams')) {
247
+ pushViolation(
248
+ violations,
249
+ 'error',
250
+ 'missing_append_only_audit_rule',
251
+ 'Policy must explicitly protect .sce/audit/**/*.jsonl as file-source.'
252
+ );
253
+ }
254
+
255
+ const scannedFiles = []
256
+ .concat(collectFilesRecursive(path.join(projectPath, '.sce', 'reports'), '.sce/reports'))
257
+ .concat(collectFilesRecursive(path.join(projectPath, '.sce', 'audit'), '.sce/audit'))
258
+ .filter((relativePath) => relativePath.endsWith('.jsonl'));
259
+
260
+ const uncoveredStreams = [];
261
+ for (const relativePath of scannedFiles) {
262
+ const covered = resourceRules.some((rule) => {
263
+ const patterns = Array.isArray(rule.path_patterns) ? rule.path_patterns : [];
264
+ return patterns.some((pattern) => minimatch(relativePath, pattern, { dot: true }));
265
+ });
266
+ if (!covered) {
267
+ uncoveredStreams.push(relativePath);
268
+ pushViolation(
269
+ violations,
270
+ 'warning',
271
+ 'uncovered_append_only_stream',
272
+ `Append-only stream is not covered by any resource rule: ${relativePath}`,
273
+ { path: relativePath }
274
+ );
275
+ }
276
+ }
277
+
278
+ const errorCount = violations.filter((item) => item.severity === 'error').length;
279
+ const warningCount = violations.filter((item) => item.severity === 'warning').length;
280
+ const passed = errorCount === 0 && (!options.failOnWarning || warningCount === 0);
281
+
282
+ return {
283
+ mode: 'state-storage-tiering-audit',
284
+ project_path: projectPath,
285
+ policy_path: loaded.policyPath,
286
+ policy_exists: loaded.exists,
287
+ passed,
288
+ success: passed,
289
+ error_count: errorCount,
290
+ warning_count: warningCount,
291
+ summary: {
292
+ component_scope_count: componentScope.length,
293
+ required_component_scope_count: REQUIRED_COMPONENT_IDS.length,
294
+ resource_rule_count: resourceRules.length,
295
+ append_only_stream_count: scannedFiles.length,
296
+ uncovered_append_only_streams: uncoveredStreams.length
297
+ },
298
+ violations
299
+ };
300
+ }
301
+
302
+ function main() {
303
+ const options = parseArgs(process.argv.slice(2));
304
+ const report = auditStateStorageTiering(options);
305
+ if (options.out) {
306
+ fs.mkdirSync(path.dirname(options.out), { recursive: true });
307
+ fs.writeFileSync(options.out, JSON.stringify(report, null, 2), 'utf8');
308
+ }
309
+ if (options.json) {
310
+ console.log(JSON.stringify(report, null, 2));
311
+ } else if (report.passed) {
312
+ console.log('[state-storage-tiering-audit] passed');
313
+ } else {
314
+ console.error('[state-storage-tiering-audit] failed');
315
+ for (const violation of report.violations) {
316
+ console.error(`[state-storage-tiering-audit] ${violation.severity} ${violation.rule}: ${violation.message}`);
317
+ }
318
+ }
319
+ if (!report.passed) {
320
+ process.exitCode = 2;
321
+ }
322
+ }
323
+
324
+ if (require.main === module) {
325
+ try {
326
+ main();
327
+ } catch (error) {
328
+ console.error(error && error.message ? error.message : `${error}`);
329
+ process.exitCode = 1;
330
+ }
331
+ }
332
+
333
+ module.exports = {
334
+ auditStateStorageTiering,
335
+ loadPolicy,
336
+ parseArgs
337
+ };