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.
- package/CHANGELOG.md +25 -0
- package/bin/scene-capability-engine.js +36 -2
- package/docs/command-reference.md +5 -0
- package/docs/releases/README.md +2 -0
- package/docs/releases/v3.6.45.md +18 -0
- package/docs/releases/v3.6.46.md +23 -0
- package/docs/zh/releases/README.md +2 -0
- package/docs/zh/releases/v3.6.45.md +18 -0
- package/docs/zh/releases/v3.6.46.md +23 -0
- package/lib/workspace/collab-governance-audit.js +575 -0
- package/package.json +4 -2
- package/scripts/auto-strategy-router.js +231 -0
- package/scripts/capability-mapping-report.js +339 -0
- package/scripts/check-branding-consistency.js +140 -0
- package/scripts/check-sce-tracking.js +54 -0
- package/scripts/check-skip-allowlist.js +94 -0
- package/scripts/errorbook-registry-health-gate.js +172 -0
- package/scripts/errorbook-release-gate.js +132 -0
- package/scripts/failure-attribution-repair.js +317 -0
- package/scripts/git-managed-gate.js +464 -0
- package/scripts/interactive-approval-event-projection.js +400 -0
- package/scripts/interactive-approval-workflow.js +829 -0
- package/scripts/interactive-authorization-tier-evaluate.js +413 -0
- package/scripts/interactive-change-plan-gate.js +225 -0
- package/scripts/interactive-context-bridge.js +617 -0
- package/scripts/interactive-customization-loop.js +1690 -0
- package/scripts/interactive-dialogue-governance.js +842 -0
- package/scripts/interactive-feedback-log.js +253 -0
- package/scripts/interactive-flow-smoke.js +238 -0
- package/scripts/interactive-flow.js +1059 -0
- package/scripts/interactive-governance-report.js +1112 -0
- package/scripts/interactive-intent-build.js +707 -0
- package/scripts/interactive-loop-smoke.js +215 -0
- package/scripts/interactive-moqui-adapter.js +304 -0
- package/scripts/interactive-plan-build.js +426 -0
- package/scripts/interactive-runtime-policy-evaluate.js +495 -0
- package/scripts/interactive-work-order-build.js +552 -0
- package/scripts/matrix-regression-gate.js +167 -0
- package/scripts/moqui-core-regression-suite.js +397 -0
- package/scripts/moqui-lexicon-audit.js +651 -0
- package/scripts/moqui-matrix-remediation-phased-runner.js +865 -0
- package/scripts/moqui-matrix-remediation-queue.js +852 -0
- package/scripts/moqui-metadata-extract.js +1340 -0
- package/scripts/moqui-rebuild-gate.js +167 -0
- package/scripts/moqui-release-summary.js +729 -0
- package/scripts/moqui-standard-rebuild.js +1370 -0
- package/scripts/moqui-template-baseline-report.js +682 -0
- package/scripts/npm-package-runtime-asset-check.js +221 -0
- package/scripts/problem-closure-gate.js +441 -0
- package/scripts/release-asset-integrity-check.js +216 -0
- package/scripts/release-asset-nonempty-normalize.js +166 -0
- package/scripts/release-drift-evaluate.js +223 -0
- package/scripts/release-drift-signals.js +255 -0
- package/scripts/release-governance-snapshot-export.js +132 -0
- package/scripts/release-ops-weekly-summary.js +934 -0
- package/scripts/release-risk-remediation-bundle.js +315 -0
- package/scripts/release-weekly-ops-gate.js +423 -0
- package/scripts/state-migration-reconciliation-gate.js +110 -0
- package/scripts/state-storage-tiering-audit.js +337 -0
- package/scripts/steering-content-audit.js +393 -0
- package/scripts/symbol-evidence-locate.js +366 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs-extra');
|
|
6
|
+
const { getSceStateStore } = require('../lib/state/sce-state-store');
|
|
7
|
+
|
|
8
|
+
const DEFAULT_INPUT = '.sce/reports/interactive-approval-events.jsonl';
|
|
9
|
+
|
|
10
|
+
function parseArgs(argv = []) {
|
|
11
|
+
const options = {
|
|
12
|
+
action: null,
|
|
13
|
+
projectPath: process.cwd(),
|
|
14
|
+
input: DEFAULT_INPUT,
|
|
15
|
+
readSource: 'auto',
|
|
16
|
+
actor: null,
|
|
17
|
+
workflowId: null,
|
|
18
|
+
eventType: null,
|
|
19
|
+
approvalAction: null,
|
|
20
|
+
blocked: null,
|
|
21
|
+
limit: 20,
|
|
22
|
+
json: false,
|
|
23
|
+
failOnDrift: false,
|
|
24
|
+
failOnParseError: false
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
28
|
+
const token = argv[index];
|
|
29
|
+
const next = argv[index + 1];
|
|
30
|
+
if (token === '--action' && next) {
|
|
31
|
+
options.action = `${next}`.trim().toLowerCase();
|
|
32
|
+
index += 1;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if ((token === '--project-path' || token === '--workspace') && next) {
|
|
36
|
+
options.projectPath = path.resolve(next);
|
|
37
|
+
index += 1;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if ((token === '--input' || token === '--audit-file') && next) {
|
|
41
|
+
options.input = next;
|
|
42
|
+
index += 1;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (token === '--read-source' && next) {
|
|
46
|
+
options.readSource = `${next}`.trim().toLowerCase();
|
|
47
|
+
index += 1;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (token === '--actor' && next) {
|
|
51
|
+
options.actor = next;
|
|
52
|
+
index += 1;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if ((token === '--workflow-id' || token === '--workflow') && next) {
|
|
56
|
+
options.workflowId = next;
|
|
57
|
+
index += 1;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (token === '--event-type' && next) {
|
|
61
|
+
options.eventType = next;
|
|
62
|
+
index += 1;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if ((token === '--approval-action' || token === '--action-filter') && next) {
|
|
66
|
+
options.approvalAction = next;
|
|
67
|
+
index += 1;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (token === '--blocked') {
|
|
71
|
+
options.blocked = true;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (token === '--not-blocked') {
|
|
75
|
+
options.blocked = false;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (token === '--limit' && next) {
|
|
79
|
+
options.limit = Number.parseInt(next, 10);
|
|
80
|
+
index += 1;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (token === '--json') {
|
|
84
|
+
options.json = true;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (token === '--fail-on-drift') {
|
|
88
|
+
options.failOnDrift = true;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (token === '--fail-on-parse-error') {
|
|
92
|
+
options.failOnParseError = true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!['rebuild', 'doctor', 'query'].includes(options.action)) {
|
|
97
|
+
throw new Error('--action must be one of: rebuild, doctor, query');
|
|
98
|
+
}
|
|
99
|
+
if (!['auto', 'file', 'projection'].includes(options.readSource)) {
|
|
100
|
+
throw new Error('--read-source must be one of: auto, file, projection');
|
|
101
|
+
}
|
|
102
|
+
if (!Number.isFinite(options.limit) || options.limit < 0) {
|
|
103
|
+
throw new Error('--limit must be a non-negative integer');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return options;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function normalizeString(value) {
|
|
110
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function resolveInputPath(projectPath, input) {
|
|
114
|
+
return path.isAbsolute(input) ? input : path.resolve(projectPath, input);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function relativeProjectPath(projectPath, absolutePath) {
|
|
118
|
+
return path.relative(projectPath, absolutePath).replace(/\\/g, '/');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function readApprovalAuditFile(projectPath, input) {
|
|
122
|
+
const auditPath = resolveInputPath(projectPath, input);
|
|
123
|
+
const relativePath = relativeProjectPath(projectPath, auditPath) || path.basename(auditPath);
|
|
124
|
+
if (!await fs.pathExists(auditPath)) {
|
|
125
|
+
return {
|
|
126
|
+
auditPath,
|
|
127
|
+
relativePath,
|
|
128
|
+
exists: false,
|
|
129
|
+
events: [],
|
|
130
|
+
parseErrors: [],
|
|
131
|
+
lineCount: 0
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const content = await fs.readFile(auditPath, 'utf8');
|
|
136
|
+
const lines = content.split(/\r?\n/);
|
|
137
|
+
const events = [];
|
|
138
|
+
const parseErrors = [];
|
|
139
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
140
|
+
const line = lines[index].trim();
|
|
141
|
+
if (!line) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const raw = JSON.parse(line);
|
|
146
|
+
events.push({
|
|
147
|
+
...raw,
|
|
148
|
+
audit_file: relativePath,
|
|
149
|
+
line_no: index + 1
|
|
150
|
+
});
|
|
151
|
+
} catch (error) {
|
|
152
|
+
parseErrors.push({
|
|
153
|
+
line_no: index + 1,
|
|
154
|
+
message: error.message
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
auditPath,
|
|
161
|
+
relativePath,
|
|
162
|
+
exists: true,
|
|
163
|
+
events,
|
|
164
|
+
parseErrors,
|
|
165
|
+
lineCount: lines.filter((line) => line.trim().length > 0).length
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function filterApprovalEvents(events = [], options = {}) {
|
|
170
|
+
let rows = Array.isArray(events) ? events.slice() : [];
|
|
171
|
+
const actor = normalizeString(options.actor);
|
|
172
|
+
const workflowId = normalizeString(options.workflowId || options.workflow_id);
|
|
173
|
+
const eventType = normalizeString(options.eventType || options.event_type);
|
|
174
|
+
const approvalAction = normalizeString(options.approvalAction || options.approval_action || options.action);
|
|
175
|
+
const blocked = options.blocked;
|
|
176
|
+
|
|
177
|
+
if (actor) {
|
|
178
|
+
rows = rows.filter((item) => normalizeString(item.actor) === actor);
|
|
179
|
+
}
|
|
180
|
+
if (workflowId) {
|
|
181
|
+
rows = rows.filter((item) => normalizeString(item.workflow_id) === workflowId);
|
|
182
|
+
}
|
|
183
|
+
if (eventType) {
|
|
184
|
+
rows = rows.filter((item) => normalizeString(item.event_type) === eventType);
|
|
185
|
+
}
|
|
186
|
+
if (approvalAction) {
|
|
187
|
+
rows = rows.filter((item) => normalizeString(item.action) === approvalAction);
|
|
188
|
+
}
|
|
189
|
+
if (blocked === true || blocked === false) {
|
|
190
|
+
rows = rows.filter((item) => Boolean(item.blocked) === blocked);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
rows.sort((left, right) => {
|
|
194
|
+
const leftTs = Date.parse(left.event_timestamp || left.timestamp || '') || 0;
|
|
195
|
+
const rightTs = Date.parse(right.event_timestamp || right.timestamp || '') || 0;
|
|
196
|
+
return rightTs - leftTs;
|
|
197
|
+
});
|
|
198
|
+
return rows;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function rebuildInteractiveApprovalProjection(options = {}, dependencies = {}) {
|
|
202
|
+
const projectPath = path.resolve(options.projectPath || process.cwd());
|
|
203
|
+
const stateStore = dependencies.stateStore || getSceStateStore(projectPath, {
|
|
204
|
+
fileSystem: dependencies.fileSystem || fs,
|
|
205
|
+
env: dependencies.env || process.env
|
|
206
|
+
});
|
|
207
|
+
const audit = await readApprovalAuditFile(projectPath, options.input || DEFAULT_INPUT);
|
|
208
|
+
|
|
209
|
+
await stateStore.clearInteractiveApprovalEventProjection({
|
|
210
|
+
auditFile: audit.relativePath
|
|
211
|
+
});
|
|
212
|
+
const writeResult = await stateStore.upsertInteractiveApprovalEventProjection(audit.events, {
|
|
213
|
+
source: 'jsonl.interactive-approval-events',
|
|
214
|
+
auditFile: audit.relativePath
|
|
215
|
+
});
|
|
216
|
+
const projectionRows = await stateStore.listInteractiveApprovalEventProjection({
|
|
217
|
+
auditFile: audit.relativePath,
|
|
218
|
+
limit: 0
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
mode: 'interactive-approval-event-projection',
|
|
223
|
+
action: 'rebuild',
|
|
224
|
+
success: audit.parseErrors.length === 0,
|
|
225
|
+
passed: audit.parseErrors.length === 0,
|
|
226
|
+
project_path: projectPath,
|
|
227
|
+
audit_file: audit.relativePath,
|
|
228
|
+
source_event_count: audit.events.length,
|
|
229
|
+
projection_event_count: Array.isArray(projectionRows) ? projectionRows.length : 0,
|
|
230
|
+
parse_error_count: audit.parseErrors.length,
|
|
231
|
+
parse_errors: audit.parseErrors,
|
|
232
|
+
write_result: writeResult || null
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function doctorInteractiveApprovalProjection(options = {}, dependencies = {}) {
|
|
237
|
+
const projectPath = path.resolve(options.projectPath || process.cwd());
|
|
238
|
+
const stateStore = dependencies.stateStore || getSceStateStore(projectPath, {
|
|
239
|
+
fileSystem: dependencies.fileSystem || fs,
|
|
240
|
+
env: dependencies.env || process.env
|
|
241
|
+
});
|
|
242
|
+
const audit = await readApprovalAuditFile(projectPath, options.input || DEFAULT_INPUT);
|
|
243
|
+
const projectionRows = await stateStore.listInteractiveApprovalEventProjection({
|
|
244
|
+
auditFile: audit.relativePath,
|
|
245
|
+
limit: 0
|
|
246
|
+
});
|
|
247
|
+
const projectionCount = Array.isArray(projectionRows) ? projectionRows.length : 0;
|
|
248
|
+
|
|
249
|
+
let status = 'aligned';
|
|
250
|
+
if (audit.parseErrors.length > 0) {
|
|
251
|
+
status = 'parse-error';
|
|
252
|
+
} else if (!audit.exists && projectionCount === 0) {
|
|
253
|
+
status = 'empty';
|
|
254
|
+
} else if (!audit.exists && projectionCount > 0) {
|
|
255
|
+
status = 'projection-only';
|
|
256
|
+
} else if (audit.events.length === 0 && projectionCount === 0) {
|
|
257
|
+
status = 'empty';
|
|
258
|
+
} else if (projectionCount === 0 && audit.events.length > 0) {
|
|
259
|
+
status = 'projection-missing';
|
|
260
|
+
} else if (projectionCount < audit.events.length) {
|
|
261
|
+
status = 'pending-projection';
|
|
262
|
+
} else if (projectionCount > audit.events.length) {
|
|
263
|
+
status = 'projection-ahead';
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const latestSourceEvent = audit.events.length > 0 ? filterApprovalEvents(audit.events, { limit: 1 })[0] : null;
|
|
267
|
+
const latestProjectionEvent = projectionCount > 0 ? projectionRows[0] : null;
|
|
268
|
+
|
|
269
|
+
const blocking = [];
|
|
270
|
+
const alerts = [];
|
|
271
|
+
if (status === 'parse-error') {
|
|
272
|
+
blocking.push('parse-error');
|
|
273
|
+
}
|
|
274
|
+
if (status === 'projection-ahead') {
|
|
275
|
+
blocking.push('projection-ahead');
|
|
276
|
+
}
|
|
277
|
+
if (status === 'projection-only') {
|
|
278
|
+
blocking.push('projection-only');
|
|
279
|
+
}
|
|
280
|
+
if (status === 'projection-missing' || status === 'pending-projection') {
|
|
281
|
+
alerts.push(status);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const passed = blocking.length === 0
|
|
285
|
+
&& (!options.failOnDrift || alerts.length === 0)
|
|
286
|
+
&& (!options.failOnParseError || audit.parseErrors.length === 0);
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
mode: 'interactive-approval-event-projection',
|
|
290
|
+
action: 'doctor',
|
|
291
|
+
success: passed,
|
|
292
|
+
passed,
|
|
293
|
+
project_path: projectPath,
|
|
294
|
+
audit_file: audit.relativePath,
|
|
295
|
+
status,
|
|
296
|
+
source_event_count: audit.events.length,
|
|
297
|
+
projection_event_count: projectionCount,
|
|
298
|
+
parse_error_count: audit.parseErrors.length,
|
|
299
|
+
parse_errors: audit.parseErrors,
|
|
300
|
+
latest_source_event_id: latestSourceEvent ? latestSourceEvent.event_id || null : null,
|
|
301
|
+
latest_projection_event_id: latestProjectionEvent ? latestProjectionEvent.event_id || null : null,
|
|
302
|
+
blocking,
|
|
303
|
+
alerts
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function queryInteractiveApprovalProjection(options = {}, dependencies = {}) {
|
|
308
|
+
const projectPath = path.resolve(options.projectPath || process.cwd());
|
|
309
|
+
const stateStore = dependencies.stateStore || getSceStateStore(projectPath, {
|
|
310
|
+
fileSystem: dependencies.fileSystem || fs,
|
|
311
|
+
env: dependencies.env || process.env
|
|
312
|
+
});
|
|
313
|
+
const audit = await readApprovalAuditFile(projectPath, options.input || DEFAULT_INPUT);
|
|
314
|
+
|
|
315
|
+
let readSource = options.readSource || 'auto';
|
|
316
|
+
let rows = [];
|
|
317
|
+
if (readSource === 'projection' || readSource === 'auto') {
|
|
318
|
+
const projectionRows = await stateStore.listInteractiveApprovalEventProjection({
|
|
319
|
+
auditFile: audit.relativePath,
|
|
320
|
+
actor: options.actor,
|
|
321
|
+
workflowId: options.workflowId,
|
|
322
|
+
eventType: options.eventType,
|
|
323
|
+
action: options.approvalAction,
|
|
324
|
+
blocked: options.blocked,
|
|
325
|
+
limit: options.limit
|
|
326
|
+
});
|
|
327
|
+
if (readSource === 'projection') {
|
|
328
|
+
rows = Array.isArray(projectionRows) ? projectionRows : [];
|
|
329
|
+
} else if (Array.isArray(projectionRows) && projectionRows.length > 0) {
|
|
330
|
+
readSource = 'projection';
|
|
331
|
+
rows = projectionRows;
|
|
332
|
+
} else {
|
|
333
|
+
readSource = 'file';
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (readSource === 'file') {
|
|
338
|
+
rows = filterApprovalEvents(audit.events, {
|
|
339
|
+
actor: options.actor,
|
|
340
|
+
workflowId: options.workflowId,
|
|
341
|
+
eventType: options.eventType,
|
|
342
|
+
approvalAction: options.approvalAction,
|
|
343
|
+
blocked: options.blocked
|
|
344
|
+
}).slice(0, options.limit > 0 ? options.limit : undefined);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
mode: 'interactive-approval-event-projection',
|
|
349
|
+
action: 'query',
|
|
350
|
+
success: true,
|
|
351
|
+
passed: true,
|
|
352
|
+
project_path: projectPath,
|
|
353
|
+
audit_file: audit.relativePath,
|
|
354
|
+
read_source: readSource,
|
|
355
|
+
result_count: rows.length,
|
|
356
|
+
results: rows
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async function run(options = {}, dependencies = {}) {
|
|
361
|
+
if (options.action === 'rebuild') {
|
|
362
|
+
return rebuildInteractiveApprovalProjection(options, dependencies);
|
|
363
|
+
}
|
|
364
|
+
if (options.action === 'doctor') {
|
|
365
|
+
return doctorInteractiveApprovalProjection(options, dependencies);
|
|
366
|
+
}
|
|
367
|
+
return queryInteractiveApprovalProjection(options, dependencies);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
async function main() {
|
|
371
|
+
const options = parseArgs(process.argv.slice(2));
|
|
372
|
+
const result = await run(options);
|
|
373
|
+
if (options.json) {
|
|
374
|
+
console.log(JSON.stringify(result, null, 2));
|
|
375
|
+
} else if (options.action === 'query') {
|
|
376
|
+
console.log(`[interactive-approval-event-projection] read_source=${result.read_source} result_count=${result.result_count}`);
|
|
377
|
+
} else {
|
|
378
|
+
console.log(`[interactive-approval-event-projection] action=${options.action} status=${result.passed ? 'passed' : 'failed'}`);
|
|
379
|
+
}
|
|
380
|
+
if (!result.passed) {
|
|
381
|
+
process.exitCode = 2;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (require.main === module) {
|
|
386
|
+
main().catch((error) => {
|
|
387
|
+
console.error(error && error.message ? error.message : `${error}`);
|
|
388
|
+
process.exitCode = 1;
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
module.exports = {
|
|
393
|
+
DEFAULT_INPUT,
|
|
394
|
+
doctorInteractiveApprovalProjection,
|
|
395
|
+
parseArgs,
|
|
396
|
+
queryInteractiveApprovalProjection,
|
|
397
|
+
readApprovalAuditFile,
|
|
398
|
+
rebuildInteractiveApprovalProjection,
|
|
399
|
+
run
|
|
400
|
+
};
|