scene-capability-engine 3.6.45 → 3.6.47
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 +22 -0
- package/README.md +1 -0
- package/README.zh.md +1 -0
- package/docs/agent-runtime/symbol-evidence.schema.json +1 -1
- package/docs/command-reference.md +8 -0
- package/docs/interactive-customization/dialogue-governance-policy-baseline.json +4 -1
- package/docs/interactive-customization/embedded-assistant-authorization-dialogue-rules.md +5 -0
- package/docs/releases/README.md +2 -0
- package/docs/releases/v3.6.46.md +23 -0
- package/docs/releases/v3.6.47.md +23 -0
- package/docs/sce-business-mode-map.md +2 -1
- package/docs/sce-capability-matrix-e2e-example.md +2 -1
- package/docs/security-governance-default-baseline.md +2 -0
- package/docs/starter-kit/README.md +3 -0
- package/docs/zh/releases/README.md +2 -0
- package/docs/zh/releases/v3.6.46.md +23 -0
- package/docs/zh/releases/v3.6.47.md +23 -0
- package/lib/workspace/takeover-baseline.js +293 -1
- package/package.json +6 -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/clarification-first-audit.js +322 -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 +873 -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 +370 -0
- package/template/.sce/README.md +1 -0
- package/template/.sce/steering/CORE_PRINCIPLES.md +25 -0
|
@@ -12,6 +12,122 @@ const {
|
|
|
12
12
|
} = require('../state/state-storage-policy');
|
|
13
13
|
|
|
14
14
|
const TAKEOVER_BASELINE_SCHEMA_VERSION = '1.0';
|
|
15
|
+
const CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING = '## 11. 业务场景未知时必须先澄清,禁止直接彻底禁用';
|
|
16
|
+
const CLARIFICATION_FIRST_CORE_PRINCIPLE_SECTION = [
|
|
17
|
+
CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING,
|
|
18
|
+
'',
|
|
19
|
+
'- 不了解业务场景、模块、页面、实体或业务约束时,默认动作是先补上下文、缩小范围、生成澄清问题。',
|
|
20
|
+
'- 禁止把“未知业务场景”直接等同于 `deny`、`disable`、answer-only 或其他一刀切兜底禁用。',
|
|
21
|
+
'- 只有在明确命中安全/权限/合规/破坏性规则后,才允许进入阻断;否则必须先完成业务范围澄清。',
|
|
22
|
+
'- 这条规则适用于所有接入 SCE 的项目、模式和交互面,不允许按项目例外绕过。'
|
|
23
|
+
].join('\n');
|
|
24
|
+
const NO_BLIND_FIX_CORE_PRINCIPLE_HEADING = '## 12. 禁止盲改问题,必须先建立问题契约和证据';
|
|
25
|
+
const NO_BLIND_FIX_CORE_PRINCIPLE_SECTION = [
|
|
26
|
+
NO_BLIND_FIX_CORE_PRINCIPLE_HEADING,
|
|
27
|
+
'',
|
|
28
|
+
'- 修改问题前,必须先明确现象、复现条件、影响范围、预期行为和验证方式。',
|
|
29
|
+
'- 缺少日志、数据、接口样本、最小复现或问题契约时,应先补证据,不得靠猜测连续改代码碰运气。',
|
|
30
|
+
'- 若两轮修改仍未收敛,必须回到调试、定位和根因分析,禁止在未理解问题前盲目扩大改动面。'
|
|
31
|
+
].join('\n');
|
|
32
|
+
const STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING = '## 13. Steering 条目变更必须先评估,禁止随意增删';
|
|
33
|
+
const STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_SECTION = [
|
|
34
|
+
STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING,
|
|
35
|
+
'',
|
|
36
|
+
'- 新增、删除或重写 steering 条目前,必须先评估它是否真属于长期原则,是否与现有条目重复,是否应迁移到 `CURRENT_CONTEXT.md`、Spec 或项目文档。',
|
|
37
|
+
'- steering 变更必须说明触发原因、适用范围以及与现有规则的关系;未经评估,不得把临时偏好、短期任务或偶发结论直接固化进去。',
|
|
38
|
+
'- 接管、升级和治理脚本只能补齐基线、修复漂移,不能把未经评估的项目习惯直接塞进 steering。'
|
|
39
|
+
].join('\n');
|
|
40
|
+
const BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING = '## 14. 问题修复时前后端接口不一致默认以后端契约为准';
|
|
41
|
+
const BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION = [
|
|
42
|
+
BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING,
|
|
43
|
+
'',
|
|
44
|
+
'- 在修改问题的场景下,若前端调用后端 API 出现路径、方法、字段、状态码或响应结构不匹配,默认以后端现有接口契约为准。',
|
|
45
|
+
'- 除非明确要求新建接口或修改后端接口,否则禁止为了迁就前端错误调用去随意改后端实现或契约。',
|
|
46
|
+
'- 默认优先修正前端请求、映射、类型和兼容处理,使其与后端接口保持一致;若怀疑后端契约错误,应先确认再改。'
|
|
47
|
+
].join('\n');
|
|
48
|
+
const REQUIRED_CORE_PRINCIPLE_SECTIONS = Object.freeze([
|
|
49
|
+
{
|
|
50
|
+
heading: CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING,
|
|
51
|
+
section: CLARIFICATION_FIRST_CORE_PRINCIPLE_SECTION
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
heading: NO_BLIND_FIX_CORE_PRINCIPLE_HEADING,
|
|
55
|
+
section: NO_BLIND_FIX_CORE_PRINCIPLE_SECTION
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
heading: STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING,
|
|
59
|
+
section: STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_SECTION
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
heading: BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING,
|
|
63
|
+
section: BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION
|
|
64
|
+
}
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
const ERRORBOOK_REGISTRY_DEFAULTS = Object.freeze({
|
|
68
|
+
enabled: true,
|
|
69
|
+
search_mode: 'remote',
|
|
70
|
+
cache_file: '.sce/errorbook/registry-cache.json',
|
|
71
|
+
sources: [
|
|
72
|
+
{
|
|
73
|
+
name: 'central',
|
|
74
|
+
enabled: true,
|
|
75
|
+
url: 'https://raw.githubusercontent.com/heguangyong/sce-errorbook-registry/main/registry/errorbook-registry.json',
|
|
76
|
+
index_url: 'https://raw.githubusercontent.com/heguangyong/sce-errorbook-registry/main/registry/errorbook-registry.index.json'
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const ERRORBOOK_CONVERGENCE_DEFAULTS = Object.freeze({
|
|
82
|
+
enabled: true,
|
|
83
|
+
canonical_mechanism: 'errorbook',
|
|
84
|
+
absorb_project_defined_mechanisms: true,
|
|
85
|
+
disallow_parallel_mechanisms: true,
|
|
86
|
+
intake_inventory_path: '.sce/errorbook/project-intake/custom-mechanism-inventory.json',
|
|
87
|
+
strategy: 'absorb_into_sce_errorbook'
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const ERRORBOOK_PARALLEL_MECHANISM_KEYWORDS = Object.freeze([
|
|
91
|
+
'错题本',
|
|
92
|
+
'错题',
|
|
93
|
+
'故障复盘',
|
|
94
|
+
'事故复盘',
|
|
95
|
+
'问题复盘',
|
|
96
|
+
'复盘册',
|
|
97
|
+
'mistake-book',
|
|
98
|
+
'mistake_book',
|
|
99
|
+
'mistakebook',
|
|
100
|
+
'fault-book',
|
|
101
|
+
'fault_book',
|
|
102
|
+
'postmortem',
|
|
103
|
+
'post-mortem',
|
|
104
|
+
'lessons-learned',
|
|
105
|
+
'lessons_learned',
|
|
106
|
+
'defect-ledger',
|
|
107
|
+
'defect_ledger',
|
|
108
|
+
'issue-ledger',
|
|
109
|
+
'issue_ledger',
|
|
110
|
+
'incident-review',
|
|
111
|
+
'incident_review'
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
const ERRORBOOK_SCAN_IGNORED_DIRS = new Set([
|
|
115
|
+
'.git',
|
|
116
|
+
'.hg',
|
|
117
|
+
'.svn',
|
|
118
|
+
'.sce',
|
|
119
|
+
'node_modules',
|
|
120
|
+
'dist',
|
|
121
|
+
'build',
|
|
122
|
+
'coverage',
|
|
123
|
+
'.next',
|
|
124
|
+
'.turbo',
|
|
125
|
+
'.idea',
|
|
126
|
+
'.vscode',
|
|
127
|
+
'tmp',
|
|
128
|
+
'temp',
|
|
129
|
+
'.tmp'
|
|
130
|
+
]);
|
|
15
131
|
|
|
16
132
|
const SESSION_GOVERNANCE_DEFAULTS = Object.freeze({
|
|
17
133
|
schema_version: '1.0',
|
|
@@ -217,6 +333,7 @@ const TAKEOVER_DEFAULTS = Object.freeze({
|
|
|
217
333
|
max_direct_fix_rounds_before_debug: 2,
|
|
218
334
|
forbid_bypass_workarounds: true
|
|
219
335
|
},
|
|
336
|
+
errorbook_convergence: _clone(ERRORBOOK_CONVERGENCE_DEFAULTS),
|
|
220
337
|
migration_policy: {
|
|
221
338
|
legacy_kiro_supported: false,
|
|
222
339
|
require_manual_legacy_migration_confirmation: true
|
|
@@ -335,6 +452,113 @@ function _buildTakeoverBaselineConfig(existing, sceVersion) {
|
|
|
335
452
|
};
|
|
336
453
|
}
|
|
337
454
|
|
|
455
|
+
function _buildErrorbookRegistryConfig(existing) {
|
|
456
|
+
const base = _isObject(existing) ? _clone(existing) : {};
|
|
457
|
+
return {
|
|
458
|
+
..._clone(ERRORBOOK_REGISTRY_DEFAULTS),
|
|
459
|
+
...base,
|
|
460
|
+
sources: Array.isArray(base.sources) && base.sources.length > 0
|
|
461
|
+
? _clone(base.sources)
|
|
462
|
+
: _clone(ERRORBOOK_REGISTRY_DEFAULTS.sources)
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function _normalizeRelativePath(value) {
|
|
467
|
+
return `${value || ''}`.replace(/\\/g, '/');
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function _findParallelErrorbookKeyword(relativePath) {
|
|
471
|
+
const normalized = _normalizeRelativePath(relativePath).toLowerCase();
|
|
472
|
+
return ERRORBOOK_PARALLEL_MECHANISM_KEYWORDS.find((keyword) => normalized.includes(keyword.toLowerCase())) || null;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function _shouldSkipErrorbookScanDir(dirName) {
|
|
476
|
+
return ERRORBOOK_SCAN_IGNORED_DIRS.has(`${dirName || ''}`.trim());
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
async function _scanProjectDefinedErrorbookMechanisms(projectPath, fileSystem, currentDir = projectPath, depth = 0, findings = []) {
|
|
480
|
+
let entries = [];
|
|
481
|
+
try {
|
|
482
|
+
entries = await fileSystem.readdir(currentDir, { withFileTypes: true });
|
|
483
|
+
} catch (_error) {
|
|
484
|
+
return findings;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
for (const entry of entries) {
|
|
488
|
+
const absolutePath = path.join(currentDir, entry.name);
|
|
489
|
+
const relativePath = _toRelativePosix(projectPath, absolutePath);
|
|
490
|
+
|
|
491
|
+
if (entry.isDirectory()) {
|
|
492
|
+
if (_shouldSkipErrorbookScanDir(entry.name)) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const keyword = _findParallelErrorbookKeyword(relativePath);
|
|
497
|
+
if (keyword) {
|
|
498
|
+
findings.push({
|
|
499
|
+
path: relativePath,
|
|
500
|
+
kind: 'directory',
|
|
501
|
+
keyword,
|
|
502
|
+
action: 'absorb_into_sce_errorbook'
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (depth < 5) {
|
|
507
|
+
await _scanProjectDefinedErrorbookMechanisms(projectPath, fileSystem, absolutePath, depth + 1, findings);
|
|
508
|
+
}
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (!entry.isFile()) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const keyword = _findParallelErrorbookKeyword(relativePath);
|
|
517
|
+
if (!keyword) {
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
findings.push({
|
|
522
|
+
path: relativePath,
|
|
523
|
+
kind: 'file',
|
|
524
|
+
keyword,
|
|
525
|
+
action: 'absorb_into_sce_errorbook'
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return findings;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function _dedupeFindings(findings = []) {
|
|
533
|
+
const seen = new Set();
|
|
534
|
+
return findings.filter((item) => {
|
|
535
|
+
const key = `${item.kind}:${item.path}`;
|
|
536
|
+
if (seen.has(key)) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
seen.add(key);
|
|
540
|
+
return true;
|
|
541
|
+
}).sort((left, right) => `${left.path}`.localeCompare(`${right.path}`));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function _buildErrorbookConvergenceInventory(sceVersion, findings = []) {
|
|
545
|
+
const dedupedFindings = _dedupeFindings(findings);
|
|
546
|
+
return {
|
|
547
|
+
schema_version: TAKEOVER_BASELINE_SCHEMA_VERSION,
|
|
548
|
+
canonical_mechanism: 'errorbook',
|
|
549
|
+
strategy: 'absorb_into_sce_errorbook',
|
|
550
|
+
last_aligned_sce_version: sceVersion,
|
|
551
|
+
summary: {
|
|
552
|
+
detected_custom_mechanisms: dedupedFindings.length
|
|
553
|
+
},
|
|
554
|
+
guidance: [
|
|
555
|
+
'Absorb reusable failure-remediation knowledge into .sce/errorbook instead of keeping project-defined parallel mistake-book flows.',
|
|
556
|
+
'Use `sce errorbook record` for curated entries and `sce errorbook incident *` for short trial-and-error loops before curation.'
|
|
557
|
+
],
|
|
558
|
+
findings: dedupedFindings
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
338
562
|
async function _reconcileJsonFile(filePath, desired, options = {}) {
|
|
339
563
|
const {
|
|
340
564
|
projectPath,
|
|
@@ -403,6 +627,37 @@ async function _reconcileSteeringContract(projectPath, options = {}) {
|
|
|
403
627
|
};
|
|
404
628
|
}
|
|
405
629
|
|
|
630
|
+
async function _reconcileCorePrinciplesBaseline(projectPath, options = {}) {
|
|
631
|
+
const { apply, fileSystem } = options;
|
|
632
|
+
const corePrinciplesPath = path.join(projectPath, SCE_STEERING_DIR, DEFAULT_LAYER_FILES.core_principles);
|
|
633
|
+
const exists = await fileSystem.pathExists(corePrinciplesPath);
|
|
634
|
+
const existingContent = exists ? await fileSystem.readFile(corePrinciplesPath, 'utf8') : '';
|
|
635
|
+
const missingSections = REQUIRED_CORE_PRINCIPLE_SECTIONS.filter(({ heading }) => !existingContent.includes(heading));
|
|
636
|
+
const changed = missingSections.length > 0;
|
|
637
|
+
|
|
638
|
+
if (apply && changed) {
|
|
639
|
+
const normalized = `${existingContent || ''}`.trimEnd();
|
|
640
|
+
const appendedSections = missingSections.map((item) => item.section).join('\n\n');
|
|
641
|
+
const nextContent = normalized
|
|
642
|
+
? `${normalized}\n\n${appendedSections}\n`
|
|
643
|
+
: `${appendedSections}\n`;
|
|
644
|
+
await fileSystem.ensureDir(path.dirname(corePrinciplesPath));
|
|
645
|
+
await fileSystem.writeFile(corePrinciplesPath, nextContent, 'utf8');
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return {
|
|
649
|
+
path: _toRelativePosix(projectPath, corePrinciplesPath),
|
|
650
|
+
existed: exists,
|
|
651
|
+
changed,
|
|
652
|
+
status: !exists ? (changed ? 'created' : 'unchanged') : (changed ? 'updated' : 'unchanged'),
|
|
653
|
+
managed_by: 'takeover-baseline',
|
|
654
|
+
details: {
|
|
655
|
+
missing_required_headings_before: missingSections.map((item) => item.heading),
|
|
656
|
+
required_headings: REQUIRED_CORE_PRINCIPLE_SECTIONS.map((item) => item.heading)
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
|
|
406
661
|
function _summarize(items) {
|
|
407
662
|
const summary = {
|
|
408
663
|
created: 0,
|
|
@@ -477,33 +732,38 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
|
|
|
477
732
|
const adoptionPath = path.join(sceRoot, 'adoption-config.json');
|
|
478
733
|
const autoConfigPath = path.join(sceRoot, 'auto', 'config.json');
|
|
479
734
|
const takeoverConfigPath = path.join(sceRoot, 'config', 'takeover-baseline.json');
|
|
735
|
+
const errorbookRegistryPath = path.join(sceRoot, 'config', 'errorbook-registry.json');
|
|
480
736
|
const sessionGovernancePath = path.join(sceRoot, 'config', 'session-governance.json');
|
|
481
737
|
const specDomainPolicyPath = path.join(sceRoot, 'config', 'spec-domain-policy.json');
|
|
482
738
|
const problemEvalPolicyPath = path.join(sceRoot, 'config', 'problem-eval-policy.json');
|
|
483
739
|
const problemClosurePolicyPath = path.join(sceRoot, 'config', 'problem-closure-policy.json');
|
|
484
740
|
const studioIntakePolicyPath = path.join(sceRoot, 'config', 'studio-intake-policy.json');
|
|
485
741
|
const stateStoragePolicyPath = path.join(sceRoot, 'config', 'state-storage-policy.json');
|
|
742
|
+
const errorbookInventoryPath = path.join(sceRoot, 'errorbook', 'project-intake', 'custom-mechanism-inventory.json');
|
|
486
743
|
const reportPath = path.join(sceRoot, 'reports', 'takeover-baseline-latest.json');
|
|
487
744
|
|
|
488
745
|
const existingAdoption = await _readJsonSafe(adoptionPath, fileSystem);
|
|
489
746
|
const existingAuto = await _readJsonSafe(autoConfigPath, fileSystem);
|
|
490
747
|
const existingTakeover = await _readJsonSafe(takeoverConfigPath, fileSystem);
|
|
748
|
+
const existingErrorbookRegistry = await _readJsonSafe(errorbookRegistryPath, fileSystem);
|
|
491
749
|
const existingSessionGovernance = await _readJsonSafe(sessionGovernancePath, fileSystem);
|
|
492
750
|
const existingSpecDomainPolicy = await _readJsonSafe(specDomainPolicyPath, fileSystem);
|
|
493
751
|
const existingProblemEvalPolicy = await _readJsonSafe(problemEvalPolicyPath, fileSystem);
|
|
494
752
|
const existingProblemClosurePolicy = await _readJsonSafe(problemClosurePolicyPath, fileSystem);
|
|
495
753
|
const existingStudioIntakePolicy = await _readJsonSafe(studioIntakePolicyPath, fileSystem);
|
|
496
754
|
const existingStateStoragePolicy = await _readJsonSafe(stateStoragePolicyPath, fileSystem);
|
|
497
|
-
|
|
498
755
|
const desiredAdoption = _buildAdoptionConfig(existingAdoption, nowIso, sceVersion);
|
|
499
756
|
const desiredAutoConfig = _buildAutoConfig(existingAuto);
|
|
500
757
|
const desiredTakeover = _buildTakeoverBaselineConfig(existingTakeover, sceVersion);
|
|
758
|
+
const desiredErrorbookRegistry = _buildErrorbookRegistryConfig(existingErrorbookRegistry);
|
|
501
759
|
const desiredSessionGovernance = _deepMerge(existingSessionGovernance || {}, SESSION_GOVERNANCE_DEFAULTS);
|
|
502
760
|
const desiredSpecDomainPolicy = _deepMerge(existingSpecDomainPolicy || {}, SPEC_DOMAIN_POLICY_DEFAULTS);
|
|
503
761
|
const desiredProblemEvalPolicy = _deepMerge(existingProblemEvalPolicy || {}, PROBLEM_EVAL_POLICY_DEFAULTS);
|
|
504
762
|
const desiredProblemClosurePolicy = _deepMerge(existingProblemClosurePolicy || {}, PROBLEM_CLOSURE_POLICY_DEFAULTS);
|
|
505
763
|
const desiredStudioIntakePolicy = _deepMerge(existingStudioIntakePolicy || {}, STUDIO_INTAKE_POLICY_DEFAULTS);
|
|
506
764
|
const desiredStateStoragePolicy = _deepMerge(existingStateStoragePolicy || {}, cloneStateStoragePolicyDefaults());
|
|
765
|
+
const customErrorbookFindings = await _scanProjectDefinedErrorbookMechanisms(projectPath, fileSystem);
|
|
766
|
+
const desiredErrorbookInventory = _buildErrorbookConvergenceInventory(sceVersion, customErrorbookFindings);
|
|
507
767
|
|
|
508
768
|
const fileResults = [];
|
|
509
769
|
fileResults.push(await _reconcileJsonFile(adoptionPath, desiredAdoption, {
|
|
@@ -521,6 +781,11 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
|
|
|
521
781
|
apply,
|
|
522
782
|
fileSystem
|
|
523
783
|
}));
|
|
784
|
+
fileResults.push(await _reconcileJsonFile(errorbookRegistryPath, desiredErrorbookRegistry, {
|
|
785
|
+
projectPath,
|
|
786
|
+
apply,
|
|
787
|
+
fileSystem
|
|
788
|
+
}));
|
|
524
789
|
fileResults.push(await _reconcileJsonFile(sessionGovernancePath, desiredSessionGovernance, {
|
|
525
790
|
projectPath,
|
|
526
791
|
apply,
|
|
@@ -551,10 +816,20 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
|
|
|
551
816
|
apply,
|
|
552
817
|
fileSystem
|
|
553
818
|
}));
|
|
819
|
+
fileResults.push(await _reconcileJsonFile(errorbookInventoryPath, desiredErrorbookInventory, {
|
|
820
|
+
projectPath,
|
|
821
|
+
apply,
|
|
822
|
+
fileSystem,
|
|
823
|
+
managedBy: 'errorbook-convergence'
|
|
824
|
+
}));
|
|
554
825
|
fileResults.push(await _reconcileSteeringContract(projectPath, {
|
|
555
826
|
apply,
|
|
556
827
|
fileSystem
|
|
557
828
|
}));
|
|
829
|
+
fileResults.push(await _reconcileCorePrinciplesBaseline(projectPath, {
|
|
830
|
+
apply,
|
|
831
|
+
fileSystem
|
|
832
|
+
}));
|
|
558
833
|
|
|
559
834
|
const auditFiles = _toAuditStatus(fileResults, apply);
|
|
560
835
|
const summary = _summarize(auditFiles);
|
|
@@ -571,6 +846,12 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
|
|
|
571
846
|
sce_version: sceVersion,
|
|
572
847
|
drift_count: driftCount,
|
|
573
848
|
enforced_defaults: _clone(TAKEOVER_DEFAULTS),
|
|
849
|
+
errorbook_convergence: {
|
|
850
|
+
canonical_mechanism: 'errorbook',
|
|
851
|
+
strategy: 'absorb_into_sce_errorbook',
|
|
852
|
+
detected_custom_mechanism_count: desiredErrorbookInventory.summary.detected_custom_mechanisms,
|
|
853
|
+
inventory_file: _toRelativePosix(projectPath, errorbookInventoryPath)
|
|
854
|
+
},
|
|
574
855
|
files: auditFiles,
|
|
575
856
|
summary
|
|
576
857
|
};
|
|
@@ -595,6 +876,17 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
|
|
|
595
876
|
}
|
|
596
877
|
|
|
597
878
|
module.exports = {
|
|
879
|
+
CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING,
|
|
880
|
+
CLARIFICATION_FIRST_CORE_PRINCIPLE_SECTION,
|
|
881
|
+
NO_BLIND_FIX_CORE_PRINCIPLE_HEADING,
|
|
882
|
+
NO_BLIND_FIX_CORE_PRINCIPLE_SECTION,
|
|
883
|
+
STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING,
|
|
884
|
+
STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_SECTION,
|
|
885
|
+
BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING,
|
|
886
|
+
BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION,
|
|
887
|
+
REQUIRED_CORE_PRINCIPLE_SECTIONS,
|
|
888
|
+
ERRORBOOK_REGISTRY_DEFAULTS,
|
|
889
|
+
ERRORBOOK_CONVERGENCE_DEFAULTS,
|
|
598
890
|
TAKEOVER_BASELINE_SCHEMA_VERSION,
|
|
599
891
|
TAKEOVER_DEFAULTS,
|
|
600
892
|
SESSION_GOVERNANCE_DEFAULTS,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scene-capability-engine",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.47",
|
|
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,10 +38,13 @@
|
|
|
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",
|
|
44
|
+
"audit:clarification-first": "node scripts/clarification-first-audit.js --fail-on-violation",
|
|
42
45
|
"audit:state-storage": "node scripts/state-storage-tiering-audit.js",
|
|
43
46
|
"report:steering-audit": "node scripts/steering-content-audit.js --json",
|
|
47
|
+
"report:clarification-first-audit": "node scripts/clarification-first-audit.js --json",
|
|
44
48
|
"report:state-storage": "node scripts/state-storage-tiering-audit.js --json",
|
|
45
49
|
"report:interactive-approval-projection": "node scripts/interactive-approval-event-projection.js --action doctor --json",
|
|
46
50
|
"audit:interactive-approval-projection": "node scripts/interactive-approval-event-projection.js --action doctor --fail-on-drift --fail-on-parse-error",
|
|
@@ -82,7 +86,7 @@
|
|
|
82
86
|
"gate:release-asset-integrity": "node scripts/release-asset-integrity-check.js",
|
|
83
87
|
"report:release-risk-remediation": "node scripts/release-risk-remediation-bundle.js --json",
|
|
84
88
|
"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",
|
|
89
|
+
"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 audit:clarification-first && 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
90
|
"publish:manual": "npm publish --access public",
|
|
87
91
|
"install-global": "npm install -g .",
|
|
88
92
|
"uninstall-global": "npm uninstall -g scene-capability-engine"
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
function readJsonFile(filePath) {
|
|
8
|
+
const resolved = path.resolve(filePath);
|
|
9
|
+
if (!fs.existsSync(resolved)) {
|
|
10
|
+
throw new Error(`file not found: ${filePath}`);
|
|
11
|
+
}
|
|
12
|
+
return JSON.parse(fs.readFileSync(resolved, 'utf8'));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function toBool(value, fallback = false) {
|
|
16
|
+
if (typeof value === 'boolean') {
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
if (typeof value === 'string') {
|
|
20
|
+
const lowered = value.trim().toLowerCase();
|
|
21
|
+
if (['1', 'true', 'yes', 'y', 'on'].includes(lowered)) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
if (['0', 'false', 'no', 'n', 'off'].includes(lowered)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return fallback;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function toFiniteNumber(value, fallback = 0) {
|
|
32
|
+
const num = Number(value);
|
|
33
|
+
return Number.isFinite(num) ? num : fallback;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function normalizeInput(input = {}) {
|
|
37
|
+
const goalTypeRaw = typeof input.goal_type === 'string' ? input.goal_type.trim().toLowerCase() : '';
|
|
38
|
+
return {
|
|
39
|
+
goal_type: goalTypeRaw || 'unknown',
|
|
40
|
+
requires_write: toBool(input.requires_write, false),
|
|
41
|
+
high_risk: toBool(input.high_risk, false),
|
|
42
|
+
last_run_failed: toBool(input.last_run_failed, false),
|
|
43
|
+
has_rollback_checkpoint: toBool(input.has_rollback_checkpoint, false),
|
|
44
|
+
test_failures: toFiniteNumber(input.test_failures, 0),
|
|
45
|
+
changed_files: toFiniteNumber(input.changed_files, 0),
|
|
46
|
+
user_explicit_answer_only: toBool(input.user_explicit_answer_only, false),
|
|
47
|
+
user_explicit_rollback: toBool(input.user_explicit_rollback, false)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function resolvePolicy(policy = {}) {
|
|
52
|
+
const fallback = {
|
|
53
|
+
answer_only_goal_types: ['question', 'analysis', 'explain', 'summarize'],
|
|
54
|
+
rollback_when: {
|
|
55
|
+
require_checkpoint: true,
|
|
56
|
+
require_high_risk_or_explicit: true
|
|
57
|
+
},
|
|
58
|
+
code_fix_when_tests_fail: true
|
|
59
|
+
};
|
|
60
|
+
const answerTypes = Array.isArray(policy.answer_only_goal_types)
|
|
61
|
+
? policy.answer_only_goal_types
|
|
62
|
+
.map(item => `${item || ''}`.trim().toLowerCase())
|
|
63
|
+
.filter(Boolean)
|
|
64
|
+
: fallback.answer_only_goal_types;
|
|
65
|
+
return {
|
|
66
|
+
answer_only_goal_types: answerTypes.length > 0 ? answerTypes : fallback.answer_only_goal_types,
|
|
67
|
+
rollback_when: {
|
|
68
|
+
require_checkpoint: toBool(
|
|
69
|
+
policy.rollback_when && policy.rollback_when.require_checkpoint,
|
|
70
|
+
fallback.rollback_when.require_checkpoint
|
|
71
|
+
),
|
|
72
|
+
require_high_risk_or_explicit: toBool(
|
|
73
|
+
policy.rollback_when && policy.rollback_when.require_high_risk_or_explicit,
|
|
74
|
+
fallback.rollback_when.require_high_risk_or_explicit
|
|
75
|
+
)
|
|
76
|
+
},
|
|
77
|
+
code_fix_when_tests_fail: toBool(policy.code_fix_when_tests_fail, fallback.code_fix_when_tests_fail)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function evaluateStrategy(input = {}, policyInput = {}) {
|
|
82
|
+
const payload = normalizeInput(input);
|
|
83
|
+
const policy = resolvePolicy(policyInput);
|
|
84
|
+
const reasons = [];
|
|
85
|
+
let decision = 'answer_only';
|
|
86
|
+
let confidence = 'low';
|
|
87
|
+
|
|
88
|
+
if (payload.user_explicit_answer_only) {
|
|
89
|
+
decision = 'answer_only';
|
|
90
|
+
confidence = 'high';
|
|
91
|
+
reasons.push('explicit user instruction: answer only');
|
|
92
|
+
} else if (payload.user_explicit_rollback) {
|
|
93
|
+
const checkpointOk = !policy.rollback_when.require_checkpoint || payload.has_rollback_checkpoint;
|
|
94
|
+
const riskGateOk = !policy.rollback_when.require_high_risk_or_explicit || payload.high_risk || payload.user_explicit_rollback;
|
|
95
|
+
if (checkpointOk && riskGateOk) {
|
|
96
|
+
decision = 'rollback';
|
|
97
|
+
confidence = 'high';
|
|
98
|
+
reasons.push('explicit user instruction: rollback');
|
|
99
|
+
} else {
|
|
100
|
+
decision = 'answer_only';
|
|
101
|
+
confidence = 'medium';
|
|
102
|
+
reasons.push('rollback requested but preconditions are not met');
|
|
103
|
+
}
|
|
104
|
+
} else if (
|
|
105
|
+
payload.last_run_failed
|
|
106
|
+
&& payload.has_rollback_checkpoint
|
|
107
|
+
&& payload.high_risk
|
|
108
|
+
&& payload.changed_files > 0
|
|
109
|
+
) {
|
|
110
|
+
decision = 'rollback';
|
|
111
|
+
confidence = 'high';
|
|
112
|
+
reasons.push('last run failed with high risk and rollback checkpoint available');
|
|
113
|
+
} else if (
|
|
114
|
+
policy.answer_only_goal_types.includes(payload.goal_type)
|
|
115
|
+
&& !payload.requires_write
|
|
116
|
+
) {
|
|
117
|
+
decision = 'answer_only';
|
|
118
|
+
confidence = 'high';
|
|
119
|
+
reasons.push(`goal_type=${payload.goal_type} with no write requirement`);
|
|
120
|
+
} else if (
|
|
121
|
+
policy.code_fix_when_tests_fail
|
|
122
|
+
&& payload.test_failures > 0
|
|
123
|
+
&& payload.changed_files > 0
|
|
124
|
+
) {
|
|
125
|
+
decision = 'code_fix';
|
|
126
|
+
confidence = 'high';
|
|
127
|
+
reasons.push('tests failing after code changes, prioritize focused repair');
|
|
128
|
+
} else if (payload.requires_write || payload.goal_type === 'feature' || payload.goal_type === 'bugfix') {
|
|
129
|
+
decision = 'code_change';
|
|
130
|
+
confidence = 'medium';
|
|
131
|
+
reasons.push('write-required goal needs implementation changes');
|
|
132
|
+
} else {
|
|
133
|
+
decision = 'answer_only';
|
|
134
|
+
confidence = 'low';
|
|
135
|
+
reasons.push('insufficient signals for safe code changes');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const next_actions = [];
|
|
139
|
+
if (decision === 'rollback') {
|
|
140
|
+
next_actions.push('execute rollback to latest stable checkpoint');
|
|
141
|
+
next_actions.push('collect failure evidence before reattempt');
|
|
142
|
+
} else if (decision === 'code_fix') {
|
|
143
|
+
next_actions.push('locate failing symbols and failing tests first');
|
|
144
|
+
next_actions.push('apply minimal patch and re-run targeted tests');
|
|
145
|
+
} else if (decision === 'code_change') {
|
|
146
|
+
next_actions.push('confirm affected scope and symbol locations');
|
|
147
|
+
next_actions.push('implement change and run validation tests');
|
|
148
|
+
} else {
|
|
149
|
+
next_actions.push('answer request with evidence and constraints');
|
|
150
|
+
next_actions.push('avoid repository writes in current turn');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
mode: 'auto-strategy-router',
|
|
155
|
+
decision,
|
|
156
|
+
confidence,
|
|
157
|
+
reasons,
|
|
158
|
+
next_actions,
|
|
159
|
+
input: payload,
|
|
160
|
+
policy
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function parseArgs(argv = []) {
|
|
165
|
+
const options = {
|
|
166
|
+
input: null,
|
|
167
|
+
inputFile: '',
|
|
168
|
+
policyFile: '',
|
|
169
|
+
json: false
|
|
170
|
+
};
|
|
171
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
172
|
+
const token = argv[i];
|
|
173
|
+
if (token === '--input') {
|
|
174
|
+
options.input = argv[i + 1] || '';
|
|
175
|
+
i += 1;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (token === '--input-file') {
|
|
179
|
+
options.inputFile = argv[i + 1] || '';
|
|
180
|
+
i += 1;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (token === '--policy-file') {
|
|
184
|
+
options.policyFile = argv[i + 1] || '';
|
|
185
|
+
i += 1;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (token === '--json') {
|
|
189
|
+
options.json = true;
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (token === '-h' || token === '--help') {
|
|
193
|
+
console.log([
|
|
194
|
+
'Usage:',
|
|
195
|
+
' node scripts/auto-strategy-router.js --input-file <path> [--policy-file <path>] --json',
|
|
196
|
+
' node scripts/auto-strategy-router.js --input \'{\"goal_type\":\"bugfix\",\"requires_write\":true}\' --json'
|
|
197
|
+
].join('\n'));
|
|
198
|
+
process.exit(0);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return options;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (require.main === module) {
|
|
205
|
+
const args = parseArgs(process.argv.slice(2));
|
|
206
|
+
let inputPayload = {};
|
|
207
|
+
let policyPayload = {};
|
|
208
|
+
if (args.inputFile) {
|
|
209
|
+
inputPayload = readJsonFile(args.inputFile);
|
|
210
|
+
} else if (args.input) {
|
|
211
|
+
inputPayload = JSON.parse(args.input);
|
|
212
|
+
}
|
|
213
|
+
if (args.policyFile) {
|
|
214
|
+
policyPayload = readJsonFile(args.policyFile);
|
|
215
|
+
}
|
|
216
|
+
const result = evaluateStrategy(inputPayload, policyPayload);
|
|
217
|
+
if (args.json) {
|
|
218
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
219
|
+
} else {
|
|
220
|
+
process.stdout.write(
|
|
221
|
+
`[auto-strategy-router] decision=${result.decision} confidence=${result.confidence} reasons=${result.reasons.join('; ')}\n`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
module.exports = {
|
|
227
|
+
evaluateStrategy,
|
|
228
|
+
normalizeInput,
|
|
229
|
+
parseArgs,
|
|
230
|
+
resolvePolicy
|
|
231
|
+
};
|