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,575 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs-extra');
4
+ const path = require('path');
5
+ const { minimatch } = require('minimatch');
6
+ const { loadGitSnapshot } = require('./spec-delivery-audit');
7
+ const SteeringComplianceChecker = require('../steering/steering-compliance-checker');
8
+
9
+ const MAX_SCAN_BYTES = 256 * 1024;
10
+ const ACTIVE_TEXT_EXTENSIONS = new Set([
11
+ '.cjs',
12
+ '.js',
13
+ '.json',
14
+ '.jsx',
15
+ '.md',
16
+ '.mjs',
17
+ '.ps1',
18
+ '.sh',
19
+ '.ts',
20
+ '.tsx',
21
+ '.txt',
22
+ '.yaml',
23
+ '.yml'
24
+ ]);
25
+
26
+ const ACTIVE_TEXT_SCAN_ROOTS = Object.freeze([
27
+ '.github',
28
+ 'bin',
29
+ 'docs',
30
+ 'lib',
31
+ 'README.md',
32
+ 'README.zh.md',
33
+ 'scripts',
34
+ 'template'
35
+ ]);
36
+
37
+ const ACTIVE_TEXT_SCAN_EXCLUDES = Object.freeze([
38
+ '.git/**',
39
+ '.sce/specs/**',
40
+ 'CHANGELOG.md',
41
+ 'coverage/**',
42
+ 'dist/**',
43
+ 'build/**',
44
+ 'docs/handoffs/**',
45
+ 'docs/releases/**',
46
+ 'docs/zh/releases/**',
47
+ 'node_modules/**',
48
+ 'tests/**'
49
+ ]);
50
+
51
+ const LEGACY_REFERENCE_REGEX = /\.kiro(?:[\\/]|-workspaces\b)/;
52
+ const MULTI_AGENT_CONFIG_REFERENCE = '.sce/config/multi-agent.json';
53
+
54
+ const REQUIRED_GITIGNORE_RULES = Object.freeze([
55
+ { rule: '.sce/steering/CURRENT_CONTEXT.md', sample: '.sce/steering/CURRENT_CONTEXT.md' },
56
+ { rule: '.sce/contexts/.active', sample: '.sce/contexts/.active' },
57
+ { rule: '.sce/contexts/*/CURRENT_CONTEXT.md', sample: '.sce/contexts/alice/CURRENT_CONTEXT.md' },
58
+ { rule: '.sce/config/agent-registry.json', sample: '.sce/config/agent-registry.json' },
59
+ { rule: '.sce/config/coordination-log.json', sample: '.sce/config/coordination-log.json' },
60
+ { rule: '.sce/config/machine-id.json', sample: '.sce/config/machine-id.json' },
61
+ { rule: '.sce/specs/**/.lock', sample: '.sce/specs/demo/.lock' },
62
+ { rule: '.sce/specs/**/locks/', sample: '.sce/specs/demo/locks/1.1.lock' },
63
+ { rule: '.sce/specs/**/tasks.md.lock', sample: '.sce/specs/demo/tasks.md.lock' },
64
+ { rule: '.sce/steering/*.lock', sample: '.sce/steering/CURRENT_CONTEXT.md.lock' },
65
+ { rule: '.sce/steering/*.pending.*', sample: '.sce/steering/CURRENT_CONTEXT.md.pending.agent-1' }
66
+ ]);
67
+
68
+ const RUNTIME_TRACKED_PATTERNS = Object.freeze([
69
+ '.sce/steering/CURRENT_CONTEXT.md',
70
+ '.sce/contexts/.active',
71
+ '.sce/contexts/*/CURRENT_CONTEXT.md',
72
+ '.sce/config/agent-registry.json',
73
+ '.sce/config/coordination-log.json',
74
+ '.sce/config/machine-id.json',
75
+ '.sce/specs/**/.lock',
76
+ '.sce/specs/**/locks/**',
77
+ '.sce/specs/**/tasks.md.lock',
78
+ '.sce/steering/*.lock',
79
+ '.sce/steering/*.pending.*'
80
+ ]);
81
+
82
+ function toRelativePosix(projectRoot, targetPath) {
83
+ return path.relative(projectRoot, targetPath).replace(/\\/g, '/');
84
+ }
85
+
86
+ function normalizeRelativePath(projectRoot, candidate) {
87
+ if (typeof candidate !== 'string' || !candidate.trim()) {
88
+ return null;
89
+ }
90
+
91
+ const absolutePath = path.isAbsolute(candidate)
92
+ ? candidate
93
+ : path.join(projectRoot, candidate);
94
+ const relativePath = toRelativePosix(projectRoot, absolutePath);
95
+ if (!relativePath || relativePath.startsWith('..')) {
96
+ return null;
97
+ }
98
+ return relativePath;
99
+ }
100
+
101
+ function matchesAnyPattern(candidate, patterns) {
102
+ return patterns.some((pattern) => minimatch(candidate, pattern, { dot: true }));
103
+ }
104
+
105
+ function shouldExcludeFromActiveScan(relativePath) {
106
+ return matchesAnyPattern(relativePath, ACTIVE_TEXT_SCAN_EXCLUDES);
107
+ }
108
+
109
+ function isActiveTextCandidate(relativePath) {
110
+ if (!relativePath || shouldExcludeFromActiveScan(relativePath)) {
111
+ return false;
112
+ }
113
+
114
+ const normalized = `${relativePath}`.replace(/\\/g, '/');
115
+ const exactRoot = ACTIVE_TEXT_SCAN_ROOTS.find((item) => !item.includes('/') && item === normalized);
116
+ if (exactRoot) {
117
+ return true;
118
+ }
119
+
120
+ const underRoot = ACTIVE_TEXT_SCAN_ROOTS.some((root) => {
121
+ if (!root.includes('/')) {
122
+ return normalized.startsWith(`${root}/`);
123
+ }
124
+ return normalized === root || normalized.startsWith(`${root}/`);
125
+ });
126
+ if (!underRoot) {
127
+ return false;
128
+ }
129
+
130
+ return ACTIVE_TEXT_EXTENSIONS.has(path.extname(normalized).toLowerCase());
131
+ }
132
+
133
+ function parseGitignore(content) {
134
+ return `${content || ''}`
135
+ .split(/\r?\n/)
136
+ .map((line) => line.trim())
137
+ .filter((line) => line && !line.startsWith('#') && !line.startsWith('!'));
138
+ }
139
+
140
+ function gitignorePatternMatchesSample(pattern, sample) {
141
+ const normalizedPattern = `${pattern || ''}`.replace(/\\/g, '/').trim();
142
+ const normalizedSample = `${sample || ''}`.replace(/\\/g, '/').trim();
143
+ if (!normalizedPattern || !normalizedSample) {
144
+ return false;
145
+ }
146
+
147
+ if (normalizedPattern === normalizedSample) {
148
+ return true;
149
+ }
150
+
151
+ const matchPattern = normalizedPattern.endsWith('/')
152
+ ? `${normalizedPattern}**`
153
+ : normalizedPattern;
154
+ return minimatch(normalizedSample, matchPattern, { dot: true });
155
+ }
156
+
157
+ async function collectCandidateTextFiles(projectRoot, trackedFiles, fileSystem) {
158
+ const results = [];
159
+ const visited = new Set();
160
+
161
+ if (trackedFiles instanceof Set && trackedFiles.size > 0) {
162
+ for (const relativePath of trackedFiles) {
163
+ if (!isActiveTextCandidate(relativePath) || visited.has(relativePath)) {
164
+ continue;
165
+ }
166
+ visited.add(relativePath);
167
+ results.push(relativePath);
168
+ }
169
+ }
170
+
171
+ async function walk(relativePath) {
172
+ const absolutePath = path.join(projectRoot, relativePath);
173
+ let stats;
174
+ try {
175
+ stats = await fileSystem.stat(absolutePath);
176
+ } catch (_error) {
177
+ return;
178
+ }
179
+
180
+ if (stats.isDirectory()) {
181
+ let entries = [];
182
+ try {
183
+ entries = await fileSystem.readdir(absolutePath, { withFileTypes: true });
184
+ } catch (_error) {
185
+ return;
186
+ }
187
+ for (const entry of entries) {
188
+ const childRelative = relativePath ? `${relativePath}/${entry.name}` : entry.name;
189
+ if (shouldExcludeFromActiveScan(childRelative)) {
190
+ continue;
191
+ }
192
+ await walk(childRelative);
193
+ }
194
+ return;
195
+ }
196
+
197
+ if (!stats.isFile()) {
198
+ return;
199
+ }
200
+
201
+ if (!isActiveTextCandidate(relativePath) || visited.has(relativePath)) {
202
+ return;
203
+ }
204
+ visited.add(relativePath);
205
+ results.push(relativePath);
206
+ }
207
+
208
+ for (const root of ACTIVE_TEXT_SCAN_ROOTS) {
209
+ const normalized = normalizeRelativePath(projectRoot, root);
210
+ if (!normalized) {
211
+ continue;
212
+ }
213
+ await walk(normalized);
214
+ }
215
+
216
+ return results.sort();
217
+ }
218
+
219
+ function summarizeLine(line) {
220
+ const trimmed = `${line || ''}`.trim();
221
+ if (trimmed.length <= 160) {
222
+ return trimmed;
223
+ }
224
+ return `${trimmed.slice(0, 157)}...`;
225
+ }
226
+
227
+ async function scanActiveTextReferences(projectRoot, trackedFiles, options = {}, dependencies = {}) {
228
+ const fileSystem = dependencies.fileSystem || fs;
229
+ const candidateFiles = Array.isArray(options.candidateFiles)
230
+ ? options.candidateFiles
231
+ : await collectCandidateTextFiles(projectRoot, trackedFiles, fileSystem);
232
+
233
+ const legacyMatches = [];
234
+ const multiAgentConfigReferences = [];
235
+
236
+ for (const relativePath of candidateFiles) {
237
+ const absolutePath = path.join(projectRoot, relativePath);
238
+ let stats;
239
+ try {
240
+ stats = await fileSystem.stat(absolutePath);
241
+ } catch (_error) {
242
+ continue;
243
+ }
244
+ if (!stats.isFile() || stats.size > MAX_SCAN_BYTES) {
245
+ continue;
246
+ }
247
+
248
+ let content;
249
+ try {
250
+ content = await fileSystem.readFile(absolutePath, 'utf8');
251
+ } catch (_error) {
252
+ continue;
253
+ }
254
+
255
+ const lines = content.split(/\r?\n/);
256
+ for (let index = 0; index < lines.length; index += 1) {
257
+ const line = lines[index];
258
+ if (LEGACY_REFERENCE_REGEX.test(line)) {
259
+ legacyMatches.push({
260
+ path: relativePath,
261
+ line: index + 1,
262
+ snippet: summarizeLine(line)
263
+ });
264
+ }
265
+ if (line.includes(MULTI_AGENT_CONFIG_REFERENCE)) {
266
+ multiAgentConfigReferences.push({
267
+ path: relativePath,
268
+ line: index + 1,
269
+ snippet: summarizeLine(line)
270
+ });
271
+ }
272
+ }
273
+ }
274
+
275
+ return {
276
+ candidate_files: candidateFiles,
277
+ legacy_matches: legacyMatches,
278
+ multi_agent_config_references: multiAgentConfigReferences
279
+ };
280
+ }
281
+
282
+ async function inspectGitignore(projectRoot, options = {}, dependencies = {}) {
283
+ const fileSystem = dependencies.fileSystem || fs;
284
+ const gitignorePath = path.join(projectRoot, '.gitignore');
285
+ const exists = await fileSystem.pathExists(gitignorePath);
286
+ const report = {
287
+ file: '.gitignore',
288
+ exists,
289
+ required_rules: REQUIRED_GITIGNORE_RULES.map((item) => item.rule),
290
+ missing_rules: [],
291
+ warnings: [],
292
+ violations: [],
293
+ passed: true,
294
+ reason: 'passed'
295
+ };
296
+
297
+ if (!exists) {
298
+ report.passed = false;
299
+ report.reason = 'missing-gitignore';
300
+ report.violations.push('missing .gitignore');
301
+ return report;
302
+ }
303
+
304
+ const patterns = parseGitignore(await fileSystem.readFile(gitignorePath, 'utf8'));
305
+ report.missing_rules = REQUIRED_GITIGNORE_RULES
306
+ .filter((rule) => !patterns.some((pattern) => gitignorePatternMatchesSample(pattern, rule.sample)))
307
+ .map((rule) => rule.rule);
308
+
309
+ if (report.missing_rules.length > 0) {
310
+ report.passed = false;
311
+ report.reason = 'missing-rules';
312
+ report.violations.push(...report.missing_rules.map((rule) => `missing ignore rule: ${rule}`));
313
+ }
314
+
315
+ return report;
316
+ }
317
+
318
+ function inspectRuntimeTracking(gitSnapshot) {
319
+ const trackedFiles = gitSnapshot && gitSnapshot.tracked_files instanceof Set
320
+ ? [...gitSnapshot.tracked_files]
321
+ : [];
322
+ const trackedRuntimeFiles = trackedFiles
323
+ .filter((relativePath) => matchesAnyPattern(relativePath, RUNTIME_TRACKED_PATTERNS))
324
+ .sort();
325
+
326
+ if (!gitSnapshot || gitSnapshot.available !== true) {
327
+ return {
328
+ available: false,
329
+ tracked_runtime_files: [],
330
+ warnings: ['git repository unavailable; runtime tracking audit is advisory only'],
331
+ violations: [],
332
+ passed: true,
333
+ reason: 'git-unavailable'
334
+ };
335
+ }
336
+
337
+ const passed = trackedRuntimeFiles.length === 0;
338
+ return {
339
+ available: true,
340
+ tracked_runtime_files: trackedRuntimeFiles,
341
+ warnings: [],
342
+ violations: trackedRuntimeFiles.map((item) => `runtime/personal state tracked by git: ${item}`),
343
+ passed,
344
+ reason: passed ? 'passed' : 'tracked-runtime-files'
345
+ };
346
+ }
347
+
348
+ function validateMultiAgentConfig(payload) {
349
+ const violations = [];
350
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
351
+ violations.push('multi-agent config must be a JSON object');
352
+ return violations;
353
+ }
354
+
355
+ if (typeof payload.enabled !== 'boolean') {
356
+ violations.push('multi-agent config must declare boolean field "enabled"');
357
+ }
358
+ if (
359
+ payload.heartbeatIntervalMs !== undefined
360
+ && (!Number.isInteger(payload.heartbeatIntervalMs) || payload.heartbeatIntervalMs <= 0)
361
+ ) {
362
+ violations.push('multi-agent config field "heartbeatIntervalMs" must be a positive integer');
363
+ }
364
+ if (
365
+ payload.heartbeatTimeoutMs !== undefined
366
+ && (!Number.isInteger(payload.heartbeatTimeoutMs) || payload.heartbeatTimeoutMs <= 0)
367
+ ) {
368
+ violations.push('multi-agent config field "heartbeatTimeoutMs" must be a positive integer');
369
+ }
370
+ if (
371
+ Number.isInteger(payload.heartbeatIntervalMs)
372
+ && Number.isInteger(payload.heartbeatTimeoutMs)
373
+ && payload.heartbeatTimeoutMs <= payload.heartbeatIntervalMs
374
+ ) {
375
+ violations.push('"heartbeatTimeoutMs" must be greater than "heartbeatIntervalMs"');
376
+ }
377
+ return violations;
378
+ }
379
+
380
+ async function inspectMultiAgentConfig(projectRoot, scanResult, options = {}, dependencies = {}) {
381
+ const fileSystem = dependencies.fileSystem || fs;
382
+ const configPath = path.join(projectRoot, '.sce', 'config', 'multi-agent.json');
383
+ const exists = await fileSystem.pathExists(configPath);
384
+ const runtimeTracePatterns = [
385
+ '.sce/config/agent-registry.json',
386
+ '.sce/config/coordination-log.json',
387
+ '.sce/specs/**/locks/**',
388
+ '.sce/specs/**/tasks.md.lock',
389
+ '.sce/steering/*.lock',
390
+ '.sce/steering/*.pending.*'
391
+ ];
392
+
393
+ const runtimeTracePaths = [];
394
+ async function walk(relativePath) {
395
+ const absolutePath = path.join(projectRoot, relativePath);
396
+ let entries = [];
397
+ try {
398
+ entries = await fileSystem.readdir(absolutePath, { withFileTypes: true });
399
+ } catch (_error) {
400
+ return;
401
+ }
402
+
403
+ for (const entry of entries) {
404
+ const childRelative = `${relativePath}/${entry.name}`.replace(/\\/g, '/');
405
+ if (entry.isDirectory()) {
406
+ await walk(childRelative);
407
+ } else if (matchesAnyPattern(childRelative, runtimeTracePatterns)) {
408
+ runtimeTracePaths.push(childRelative);
409
+ }
410
+ }
411
+ }
412
+
413
+ for (const root of ['.sce/config', '.sce/specs', '.sce/steering']) {
414
+ if (await fileSystem.pathExists(path.join(projectRoot, root))) {
415
+ await walk(root);
416
+ }
417
+ }
418
+
419
+ const report = {
420
+ file: '.sce/config/multi-agent.json',
421
+ exists,
422
+ valid: false,
423
+ enabled: null,
424
+ runtime_traces: runtimeTracePaths.sort(),
425
+ reference_count: Array.isArray(scanResult?.multi_agent_config_references)
426
+ ? scanResult.multi_agent_config_references.length
427
+ : 0,
428
+ warnings: [],
429
+ violations: [],
430
+ passed: true,
431
+ reason: 'not-configured'
432
+ };
433
+
434
+ if (!exists) {
435
+ if (report.runtime_traces.length > 0) {
436
+ report.passed = false;
437
+ report.reason = 'missing-config';
438
+ report.violations.push('multi-agent runtime traces detected but .sce/config/multi-agent.json is missing');
439
+ } else if (report.reference_count > 0) {
440
+ report.reason = 'missing-config-advisory';
441
+ report.warnings.push('multi-agent config is referenced in active docs/code but project config is not seeded');
442
+ }
443
+ return report;
444
+ }
445
+
446
+ let payload;
447
+ try {
448
+ payload = await fileSystem.readJson(configPath);
449
+ } catch (error) {
450
+ report.passed = false;
451
+ report.reason = 'invalid-json';
452
+ report.violations.push(`invalid multi-agent config: ${error.message}`);
453
+ return report;
454
+ }
455
+
456
+ const validationErrors = validateMultiAgentConfig(payload);
457
+ report.valid = validationErrors.length === 0;
458
+ report.enabled = typeof payload.enabled === 'boolean' ? payload.enabled : null;
459
+ if (validationErrors.length > 0) {
460
+ report.passed = false;
461
+ report.reason = 'invalid-config';
462
+ report.violations.push(...validationErrors);
463
+ return report;
464
+ }
465
+
466
+ report.reason = 'passed';
467
+ return report;
468
+ }
469
+
470
+ function inspectSteeringBoundary(projectRoot) {
471
+ const checker = new SteeringComplianceChecker();
472
+ const steeringPath = path.join(projectRoot, '.sce', 'steering');
473
+ const result = checker.check(steeringPath);
474
+ const violations = Array.isArray(result.violations) ? result.violations : [];
475
+ return {
476
+ path: '.sce/steering',
477
+ exists: fs.existsSync(steeringPath),
478
+ compliant: result.compliant === true,
479
+ violations: violations.map((item) => {
480
+ const relativePath = item.path ? normalizeRelativePath(projectRoot, item.path) : null;
481
+ return {
482
+ type: item.type,
483
+ name: item.name,
484
+ path: relativePath
485
+ };
486
+ }),
487
+ warnings: [],
488
+ passed: result.compliant === true,
489
+ reason: result.compliant === true ? 'passed' : 'boundary-drift'
490
+ };
491
+ }
492
+
493
+ async function auditCollabGovernance(projectRoot = process.cwd(), options = {}, dependencies = {}) {
494
+ const fileSystem = dependencies.fileSystem || fs;
495
+ const gitSnapshot = loadGitSnapshot(projectRoot, { allowNoRemote: true }, dependencies);
496
+ const gitignore = await inspectGitignore(projectRoot, options, dependencies);
497
+ const runtimeTracking = inspectRuntimeTracking(gitSnapshot);
498
+ const scanResult = await scanActiveTextReferences(projectRoot, gitSnapshot.tracked_files, options, dependencies);
499
+ const multiAgent = await inspectMultiAgentConfig(projectRoot, scanResult, options, dependencies);
500
+ const steeringBoundary = inspectSteeringBoundary(projectRoot);
501
+
502
+ const legacyReferences = {
503
+ matches: scanResult.legacy_matches,
504
+ warnings: [],
505
+ violations: scanResult.legacy_matches.map((item) => `legacy .kiro reference: ${item.path}:${item.line}`),
506
+ passed: scanResult.legacy_matches.length === 0,
507
+ reason: scanResult.legacy_matches.length === 0 ? 'passed' : 'legacy-references'
508
+ };
509
+
510
+ const report = {
511
+ mode: 'workspace-collab-governance-audit',
512
+ generated_at: new Date().toISOString(),
513
+ root: projectRoot,
514
+ git: {
515
+ available: gitSnapshot.available === true,
516
+ branch: gitSnapshot.branch,
517
+ upstream: gitSnapshot.upstream,
518
+ has_target_remote: gitSnapshot.has_target_remote === true,
519
+ warnings: gitSnapshot.available === true ? gitSnapshot.warnings : []
520
+ },
521
+ gitignore,
522
+ runtime_tracking: runtimeTracking,
523
+ multi_agent: multiAgent,
524
+ legacy_references: legacyReferences,
525
+ steering_boundary: steeringBoundary,
526
+ summary: {
527
+ missing_gitignore_rules: gitignore.missing_rules.length,
528
+ tracked_runtime_files: runtimeTracking.tracked_runtime_files.length,
529
+ multi_agent_warnings: multiAgent.warnings.length,
530
+ multi_agent_violations: multiAgent.violations.length,
531
+ legacy_reference_count: legacyReferences.matches.length,
532
+ steering_boundary_violations: steeringBoundary.violations.length
533
+ },
534
+ warnings: [],
535
+ violations: [],
536
+ passed: true,
537
+ reason: 'passed'
538
+ };
539
+
540
+ report.warnings.push(...gitignore.warnings);
541
+ report.warnings.push(...(gitSnapshot.available === true ? gitSnapshot.warnings : []));
542
+ report.warnings.push(...runtimeTracking.warnings);
543
+ report.warnings.push(...multiAgent.warnings);
544
+ report.warnings.push(...legacyReferences.warnings);
545
+ report.warnings.push(...steeringBoundary.warnings);
546
+
547
+ report.violations.push(...gitignore.violations);
548
+ report.violations.push(...runtimeTracking.violations);
549
+ report.violations.push(...multiAgent.violations);
550
+ report.violations.push(...legacyReferences.violations);
551
+ report.violations.push(
552
+ ...steeringBoundary.violations.map((item) => `steering boundary violation: ${item.path || item.name}`)
553
+ );
554
+
555
+ report.passed = report.violations.length === 0;
556
+ report.reason = report.passed
557
+ ? (report.warnings.length > 0 ? 'warnings' : 'passed')
558
+ : 'violations';
559
+
560
+ return report;
561
+ }
562
+
563
+ module.exports = {
564
+ ACTIVE_TEXT_SCAN_EXCLUDES,
565
+ ACTIVE_TEXT_SCAN_ROOTS,
566
+ MULTI_AGENT_CONFIG_REFERENCE,
567
+ REQUIRED_GITIGNORE_RULES,
568
+ RUNTIME_TRACKED_PATTERNS,
569
+ auditCollabGovernance,
570
+ inspectGitignore,
571
+ inspectMultiAgentConfig,
572
+ inspectRuntimeTracking,
573
+ scanActiveTextReferences,
574
+ validateMultiAgentConfig
575
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scene-capability-engine",
3
- "version": "3.6.44",
3
+ "version": "3.6.46",
4
4
  "description": "SCE (Scene Capability Engine) - A CLI tool and npm package for spec-driven development with AI coding assistants.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -10,6 +10,7 @@
10
10
  "files": [
11
11
  "bin/",
12
12
  "lib/",
13
+ "scripts/",
13
14
  "template/",
14
15
  "!template/.sce/tools/__pycache__/",
15
16
  "!template/.sce/tools/**/*.pyc",
@@ -37,6 +38,7 @@
37
38
  "test:interactive-flow-smoke": "node scripts/interactive-flow-smoke.js --json",
38
39
  "test:skip-audit": "node scripts/check-skip-allowlist.js",
39
40
  "test:sce-tracking": "node scripts/check-sce-tracking.js",
41
+ "gate:npm-runtime-assets": "node scripts/npm-package-runtime-asset-check.js --fail-on-violation",
40
42
  "test:brand-consistency": "node scripts/check-branding-consistency.js",
41
43
  "audit:steering": "node scripts/steering-content-audit.js --fail-on-error",
42
44
  "audit:state-storage": "node scripts/state-storage-tiering-audit.js",
@@ -82,7 +84,7 @@
82
84
  "gate:release-asset-integrity": "node scripts/release-asset-integrity-check.js",
83
85
  "report:release-risk-remediation": "node scripts/release-risk-remediation-bundle.js --json",
84
86
  "report:moqui-core-regression": "node scripts/moqui-core-regression-suite.js --json",
85
- "prepublishOnly": "npm run test:release && npm run test:skip-audit && npm run test:sce-tracking && npm run test:brand-consistency && npm run audit:steering && npm run gate:git-managed && npm run gate:errorbook-registry-health && npm run gate:errorbook-release && npm run report:interactive-governance -- --fail-on-alert",
87
+ "prepublishOnly": "npm run test:release && npm run test:skip-audit && npm run test:sce-tracking && npm run gate:npm-runtime-assets && npm run test:brand-consistency && npm run audit:steering && npm run gate:git-managed && npm run gate:errorbook-registry-health && npm run gate:errorbook-release && npm run report:interactive-governance -- --fail-on-alert",
86
88
  "publish:manual": "npm publish --access public",
87
89
  "install-global": "npm install -g .",
88
90
  "uninstall-global": "npm uninstall -g scene-capability-engine"