scene-capability-engine 3.3.5 → 3.3.10
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 +130 -78
- package/README.md +6 -6
- package/README.zh.md +6 -6
- package/bin/scene-capability-engine.js +129 -7
- package/docs/331-poc-adaptation-roadmap.md +3 -3
- package/docs/331-poc-dual-track-integration-guide.md +8 -8
- package/docs/331-poc-weekly-delivery-checklist.md +6 -6
- package/docs/README.md +4 -0
- package/docs/adopt-migration-guide.md +13 -13
- package/docs/adoption-guide.md +28 -28
- package/docs/agent-hooks-analysis.md +10 -10
- package/docs/architecture.md +13 -13
- package/docs/articles/ai-driven-development-philosophy-and-practice.en.md +3 -3
- package/docs/articles/ai-driven-development-philosophy-and-practice.md +3 -3
- package/docs/autonomous-control-guide.md +35 -35
- package/docs/command-reference.md +192 -153
- package/docs/cross-tool-guide.md +7 -7
- package/docs/developer-guide.md +8 -8
- package/docs/document-governance.md +15 -15
- package/docs/environment-management-guide.md +6 -6
- package/docs/examples/add-export-command/design.md +1 -1
- package/docs/faq.md +13 -13
- package/docs/handoff-profile-integration-guide.md +3 -3
- package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.json +7 -7
- package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.md +1 -1
- package/docs/integration-modes.md +12 -12
- package/docs/integration-philosophy.md +11 -11
- package/docs/interactive-customization/331-poc-sce-integration-checklist.md +24 -24
- package/docs/interactive-customization/README.md +43 -43
- package/docs/interactive-customization/business-mode-policy-baseline.json +33 -0
- package/docs/interactive-customization/dual-ui-mode-integration-guide.md +1 -1
- package/docs/interactive-customization/moqui-adapter-interface.md +2 -2
- package/docs/interactive-customization/moqui-copilot-integration-guide.md +1 -1
- package/docs/interactive-customization/moqui-interactive-template-playbook.md +4 -4
- package/docs/interactive-customization/phase-acceptance-evidence.md +2 -2
- package/docs/knowledge-management-guide.md +6 -6
- package/docs/manual-workflows-guide.md +4 -4
- package/docs/moqui-capability-matrix.md +3 -3
- package/docs/moqui-standard-rebuild-guide.md +8 -8
- package/docs/moqui-template-core-library-playbook.md +27 -27
- package/docs/multi-agent-coordination-guide.md +19 -19
- package/docs/multi-repo-management-guide.md +17 -17
- package/docs/quick-start-with-ai-tools.md +7 -7
- package/docs/quick-start.md +2 -2
- package/docs/release-checklist.md +4 -4
- package/docs/sce-business-mode-map.md +103 -0
- package/docs/security-governance-default-baseline.md +12 -12
- package/docs/spec-collaboration-guide.md +3 -3
- package/docs/spec-locking-guide.md +2 -2
- package/docs/spec-workflow.md +3 -3
- package/docs/starter-kit/README.md +4 -4
- package/docs/starter-kit/handoff-manifest.starter.json +2 -2
- package/docs/starter-kit/release.workflow.sample.yml +1 -1
- package/docs/steering-strategy-guide.md +15 -15
- package/docs/team-collaboration-guide.md +69 -69
- package/docs/testing-strategy.md +2 -2
- package/docs/tools/claude-guide.md +14 -4
- package/docs/tools/cursor-guide.md +14 -14
- package/docs/tools/generic-guide.md +9 -9
- package/docs/tools/kiro-guide.md +4 -4
- package/docs/tools/vscode-guide.md +13 -13
- package/docs/tools/windsurf-guide.md +6 -6
- package/docs/troubleshooting.md +22 -22
- package/docs/upgrade-guide.md +8 -8
- package/docs/value-observability-guide.md +3 -3
- package/docs/zh/README.md +6 -0
- package/docs/zh/quick-start.md +15 -15
- package/docs/zh/release-checklist.md +3 -3
- package/docs/zh/tools/claude-guide.md +16 -6
- package/docs/zh/tools/cursor-guide.md +11 -11
- package/docs/zh/tools/generic-guide.md +13 -13
- package/docs/zh/tools/kiro-guide.md +2 -2
- package/docs/zh/tools/vscode-guide.md +11 -11
- package/docs/zh/tools/windsurf-guide.md +11 -11
- package/docs/zh/value-observability-guide.md +3 -3
- package/lib/adoption/adoption-logger.js +1 -1
- package/lib/adoption/adoption-strategy.js +28 -28
- package/lib/adoption/backup-manager.js +3 -3
- package/lib/adoption/conflict-resolver.js +2 -2
- package/lib/adoption/detection-engine.js +8 -8
- package/lib/adoption/error-formatter.js +4 -4
- package/lib/adoption/file-classifier.js +6 -6
- package/lib/adoption/progress-reporter.js +1 -1
- package/lib/adoption/smart-orchestrator.js +10 -10
- package/lib/adoption/strategy-selector.js +6 -6
- package/lib/adoption/summary-generator.js +1 -1
- package/lib/adoption/template-sync.js +8 -8
- package/lib/auto/autonomous-engine.js +7 -7
- package/lib/auto/checkpoint-manager.js +1 -1
- package/lib/auto/close-loop-runner.js +12 -12
- package/lib/auto/error-recovery-manager.js +1 -1
- package/lib/auto/goal-decomposer.js +1 -1
- package/lib/auto/moqui-recovery-sequence.js +2 -2
- package/lib/auto/progress-tracker.js +1 -1
- package/lib/auto/state-manager.js +1 -1
- package/lib/backup/backup-system.js +10 -10
- package/lib/backup/selective-backup.js +4 -4
- package/lib/collab/agent-registry.js +2 -2
- package/lib/collab/contract-manager.js +1 -1
- package/lib/collab/coordinator.js +2 -2
- package/lib/collab/dependency-manager.js +1 -1
- package/lib/collab/integration-manager.js +1 -1
- package/lib/collab/metadata-manager.js +1 -1
- package/lib/collab/multi-agent-config.js +2 -2
- package/lib/collab/spec-lifecycle-manager.js +2 -2
- package/lib/collab/visualizer.js +1 -1
- package/lib/commands/adopt.js +6 -6
- package/lib/commands/auto.js +56 -56
- package/lib/commands/collab.js +2 -2
- package/lib/commands/docs.js +3 -3
- package/lib/commands/doctor.js +1 -1
- package/lib/commands/knowledge.js +2 -2
- package/lib/commands/lock.js +1 -1
- package/lib/commands/ops.js +1 -1
- package/lib/commands/orchestrate.js +3 -3
- package/lib/commands/rollback.js +1 -1
- package/lib/commands/scene.js +135 -93
- package/lib/commands/session.js +139 -0
- package/lib/commands/spec-bootstrap.js +1 -1
- package/lib/commands/spec-gate.js +2 -2
- package/lib/commands/spec-pipeline.js +1 -1
- package/lib/commands/status.js +4 -4
- package/lib/commands/steering.js +119 -0
- package/lib/commands/value.js +1 -1
- package/lib/commands/watch.js +9 -9
- package/lib/commands/workspace-multi.js +1 -1
- package/lib/context/context-exporter.js +5 -7
- package/lib/context/prompt-generator.js +2 -2
- package/lib/environment/backup-system.js +1 -1
- package/lib/environment/environment-manager.js +2 -2
- package/lib/gitignore/gitignore-backup.js +3 -3
- package/lib/gitignore/gitignore-detector.js +13 -13
- package/lib/gitignore/gitignore-integration.js +3 -3
- package/lib/gitignore/gitignore-transformer.js +4 -4
- package/lib/gitignore/layered-rules-template.js +16 -16
- package/lib/governance/config-manager.js +1 -1
- package/lib/governance/doc-reference-checker.js +4 -4
- package/lib/governance/execution-logger.js +1 -1
- package/lib/governance/file-scanner.js +3 -3
- package/lib/interactive-customization/moqui-interactive-adapter.js +2 -2
- package/lib/knowledge/knowledge-manager.js +1 -1
- package/lib/lock/lock-manager.js +2 -2
- package/lib/lock/steering-file-lock.js +5 -5
- package/lib/lock/task-lock-manager.js +3 -3
- package/lib/operations/audit-logger.js +1 -1
- package/lib/operations/feedback-manager.js +1 -1
- package/lib/operations/operations-manager.js +3 -3
- package/lib/operations/permission-manager.js +2 -2
- package/lib/operations/template-loader.js +1 -1
- package/lib/orchestrator/agent-spawner.js +27 -2
- package/lib/orchestrator/bootstrap-prompt-builder.js +6 -6
- package/lib/orchestrator/orchestration-engine.js +1 -1
- package/lib/orchestrator/orchestrator-config.js +2 -2
- package/lib/repo/config-manager.js +3 -3
- package/lib/repo/handlers/init-handler.js +1 -1
- package/lib/repo/repo-manager.js +2 -2
- package/lib/runtime/business-mode-resolver.js +240 -0
- package/lib/runtime/session-store.js +207 -0
- package/lib/runtime/steering-contract.js +338 -0
- package/lib/scene-runtime/audit-emitter.js +1 -1
- package/lib/scene-runtime/binding-plugin-loader.js +3 -3
- package/lib/scene-runtime/eval-bridge.js +1 -1
- package/lib/scene-runtime/index.js +1 -1
- package/lib/scene-runtime/moqui-extractor.js +1 -1
- package/lib/scene-runtime/plan-compiler.js +1 -1
- package/lib/scene-runtime/policy-gate.js +1 -1
- package/lib/scene-runtime/runtime-executor.js +1 -1
- package/lib/scene-runtime/scene-loader.js +1 -1
- package/lib/spec/bootstrap/context-collector.js +1 -1
- package/lib/spec/pipeline/stage-adapters.js +3 -3
- package/lib/spec/pipeline/state-store.js +1 -1
- package/lib/spec-gate/policy/policy-loader.js +1 -1
- package/lib/spec-gate/rules/default-rules.js +6 -6
- package/lib/steering/adoption-config.js +1 -1
- package/lib/steering/compliance-error-reporter.js +3 -3
- package/lib/steering/context-sync-manager.js +2 -2
- package/lib/steering/index.js +1 -1
- package/lib/steering/spec-steering.js +2 -2
- package/lib/steering/steering-compliance-checker.js +1 -1
- package/lib/steering/steering-loader.js +4 -5
- package/lib/steering/steering-manager.js +4 -4
- package/lib/task/task-claimer.js +5 -5
- package/lib/task/task-status-store.js +2 -2
- package/lib/templates/content-generalizer.js +1 -1
- package/lib/templates/spec-reader.js +2 -2
- package/lib/templates/template-creator.js +1 -1
- package/lib/templates/template-exporter.js +3 -3
- package/lib/templates/template-manager.js +1 -1
- package/lib/upgrade/migration-engine.js +3 -3
- package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +1 -1
- package/lib/utils/file-diff.js +6 -6
- package/lib/utils/tool-detector.js +10 -10
- package/lib/utils/validation.js +5 -5
- package/lib/value/metric-contract-loader.js +1 -1
- package/lib/version/version-manager.js +1 -1
- package/lib/watch/execution-logger.js +1 -1
- package/lib/watch/presets.js +8 -8
- package/lib/watch/watch-manager.js +2 -2
- package/lib/workspace/legacy-kiro-migrator.js +275 -0
- package/lib/workspace/multi/workspace-context-resolver.js +2 -2
- package/lib/workspace/multi/workspace-registry.js +2 -2
- package/lib/workspace/multi/workspace-state-manager.js +3 -3
- package/lib/workspace/workspace-manager.js +1 -1
- package/lib/workspace/workspace-sync.js +2 -2
- package/locales/en.json +4 -4
- package/locales/zh.json +4 -4
- package/package.json +9 -9
- package/template/{.kiro → .sce}/README.md +15 -15
- package/template/{.kiro → .sce}/hooks/check-spec-on-create.kiro.hook +2 -2
- package/template/{.kiro → .sce}/steering/CORE_PRINCIPLES.md +4 -4
- package/template/{.kiro → .sce}/steering/CURRENT_CONTEXT.md +1 -1
- package/template/{.kiro → .sce}/steering/ENVIRONMENT.md +3 -3
- package/template/{.kiro → .sce}/tools/backup_manager.py +3 -3
- package/template/{.kiro → .sce}/tools/configuration_manager.py +1 -1
- package/template/README.md +12 -12
- /package/template/{.kiro → .sce}/hooks/run-tests-on-save.kiro.hook +0 -0
- /package/template/{.kiro → .sce}/hooks/sync-tasks-on-edit.kiro.hook +0 -0
- /package/template/{.kiro → .sce}/specs/SPEC_WORKFLOW_GUIDE.md +0 -0
- /package/template/{.kiro → .sce}/steering/RULES_GUIDE.md +0 -0
- /package/template/{.kiro → .sce}/templates/operations/default/change-impact.md +0 -0
- /package/template/{.kiro → .sce}/templates/operations/default/deployment.md +0 -0
- /package/template/{.kiro → .sce}/templates/operations/default/feedback-response.md +0 -0
- /package/template/{.kiro → .sce}/templates/operations/default/migration-plan.md +0 -0
- /package/template/{.kiro → .sce}/templates/operations/default/monitoring.md +0 -0
- /package/template/{.kiro → .sce}/templates/operations/default/operations.md +0 -0
- /package/template/{.kiro → .sce}/templates/operations/default/rollback.md +0 -0
- /package/template/{.kiro → .sce}/templates/operations/default/tools.yaml +0 -0
- /package/template/{.kiro → .sce}/templates/operations/default/troubleshooting.md +0 -0
- /package/template/{.kiro → .sce}/tools/document_evaluator.py +0 -0
- /package/template/{.kiro → .sce}/tools/enhancement_logger.py +0 -0
- /package/template/{.kiro → .sce}/tools/error_handler.py +0 -0
- /package/template/{.kiro → .sce}/tools/improvement_identifier.py +0 -0
- /package/template/{.kiro → .sce}/tools/modification_applicator.py +0 -0
- /package/template/{.kiro → .sce}/tools/quality_gate_enforcer.py +0 -0
- /package/template/{.kiro → .sce}/tools/quality_scorer.py +0 -0
- /package/template/{.kiro → .sce}/tools/report_generator.py +0 -0
- /package/template/{.kiro → .sce}/tools/ultrawork_enhancer.py +0 -0
- /package/template/{.kiro → .sce}/tools/ultrawork_enhancer_refactored.py +0 -0
- /package/template/{.kiro → .sce}/tools/ultrawork_enhancer_v2.py +0 -0
- /package/template/{.kiro → .sce}/tools/ultrawork_enhancer_v3.py +0 -0
- /package/template/{.kiro → .sce}/tools/workflow_quality_gate.py +0 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
|
|
6
|
+
const DEFAULT_BUSINESS_MODE_POLICY = 'docs/interactive-customization/business-mode-policy-baseline.json';
|
|
7
|
+
const BUSINESS_MODES = new Set(['user-mode', 'ops-mode', 'dev-mode']);
|
|
8
|
+
|
|
9
|
+
const BUILTIN_POLICY = Object.freeze({
|
|
10
|
+
version: '1.0.0',
|
|
11
|
+
defaults: {
|
|
12
|
+
mode: null,
|
|
13
|
+
enforce_alignment: true
|
|
14
|
+
},
|
|
15
|
+
modes: {
|
|
16
|
+
'user-mode': {
|
|
17
|
+
execution_mode: 'suggestion',
|
|
18
|
+
dialogue_profile: 'business-user',
|
|
19
|
+
ui_mode: 'user-app',
|
|
20
|
+
runtime_mode: 'user-assist',
|
|
21
|
+
runtime_environment: 'staging',
|
|
22
|
+
auto_execute_low_risk: false
|
|
23
|
+
},
|
|
24
|
+
'ops-mode': {
|
|
25
|
+
execution_mode: 'apply',
|
|
26
|
+
dialogue_profile: 'system-maintainer',
|
|
27
|
+
ui_mode: 'ops-console',
|
|
28
|
+
runtime_mode: 'ops-fix',
|
|
29
|
+
runtime_environment: 'staging',
|
|
30
|
+
auto_execute_low_risk: false
|
|
31
|
+
},
|
|
32
|
+
'dev-mode': {
|
|
33
|
+
execution_mode: 'apply',
|
|
34
|
+
dialogue_profile: 'system-maintainer',
|
|
35
|
+
ui_mode: 'ops-console',
|
|
36
|
+
runtime_mode: 'feature-dev',
|
|
37
|
+
runtime_environment: 'dev',
|
|
38
|
+
auto_execute_low_risk: false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
function normalizeBusinessMode(value) {
|
|
44
|
+
const normalized = `${value || ''}`.trim().toLowerCase();
|
|
45
|
+
return normalized || null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function normalizeBoolean(value, fallback = false) {
|
|
49
|
+
if (value === true || value === false) {
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
return fallback;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function sanitizeModePreset(rawPreset = {}) {
|
|
56
|
+
return {
|
|
57
|
+
execution_mode: `${rawPreset.execution_mode || ''}`.trim().toLowerCase() || null,
|
|
58
|
+
dialogue_profile: `${rawPreset.dialogue_profile || ''}`.trim().toLowerCase() || null,
|
|
59
|
+
ui_mode: `${rawPreset.ui_mode || ''}`.trim().toLowerCase() || null,
|
|
60
|
+
runtime_mode: `${rawPreset.runtime_mode || ''}`.trim().toLowerCase() || null,
|
|
61
|
+
runtime_environment: `${rawPreset.runtime_environment || ''}`.trim().toLowerCase() || null,
|
|
62
|
+
auto_execute_low_risk: normalizeBoolean(rawPreset.auto_execute_low_risk, false)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function normalizePolicy(rawPolicy = {}) {
|
|
67
|
+
const defaults = rawPolicy && typeof rawPolicy.defaults === 'object' ? rawPolicy.defaults : {};
|
|
68
|
+
const rawModes = rawPolicy && rawPolicy.modes && typeof rawPolicy.modes === 'object'
|
|
69
|
+
? rawPolicy.modes
|
|
70
|
+
: {};
|
|
71
|
+
|
|
72
|
+
const mergedModes = {};
|
|
73
|
+
for (const [modeKey, fallbackPreset] of Object.entries(BUILTIN_POLICY.modes)) {
|
|
74
|
+
const overridePreset = rawModes[modeKey] && typeof rawModes[modeKey] === 'object'
|
|
75
|
+
? rawModes[modeKey]
|
|
76
|
+
: null;
|
|
77
|
+
mergedModes[modeKey] = sanitizeModePreset({
|
|
78
|
+
...fallbackPreset,
|
|
79
|
+
...(overridePreset || {})
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
version: `${rawPolicy.version || BUILTIN_POLICY.version}`,
|
|
85
|
+
defaults: {
|
|
86
|
+
mode: normalizeBusinessMode(defaults.mode),
|
|
87
|
+
enforce_alignment: normalizeBoolean(defaults.enforce_alignment, BUILTIN_POLICY.defaults.enforce_alignment)
|
|
88
|
+
},
|
|
89
|
+
modes: mergedModes
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function loadBusinessModePolicy({ cwd, policyPath }) {
|
|
94
|
+
const policyRef = `${policyPath || DEFAULT_BUSINESS_MODE_POLICY}`.trim() || DEFAULT_BUSINESS_MODE_POLICY;
|
|
95
|
+
const resolvedPath = path.isAbsolute(policyRef) ? policyRef : path.resolve(cwd, policyRef);
|
|
96
|
+
|
|
97
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
98
|
+
return {
|
|
99
|
+
policy: normalizePolicy(BUILTIN_POLICY),
|
|
100
|
+
policy_path: resolvedPath,
|
|
101
|
+
policy_source: 'builtin'
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const rawPolicy = fs.readJsonSync(resolvedPath);
|
|
107
|
+
return {
|
|
108
|
+
policy: normalizePolicy(rawPolicy),
|
|
109
|
+
policy_path: resolvedPath,
|
|
110
|
+
policy_source: 'file'
|
|
111
|
+
};
|
|
112
|
+
} catch (_error) {
|
|
113
|
+
return {
|
|
114
|
+
policy: normalizePolicy(BUILTIN_POLICY),
|
|
115
|
+
policy_path: resolvedPath,
|
|
116
|
+
policy_source: 'builtin'
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function inferBusinessMode(options = {}) {
|
|
122
|
+
const runtimeMode = `${options.runtimeMode || ''}`.trim().toLowerCase();
|
|
123
|
+
const dialogueProfile = `${options.dialogueProfile || ''}`.trim().toLowerCase();
|
|
124
|
+
const executionMode = `${options.executionMode || ''}`.trim().toLowerCase();
|
|
125
|
+
|
|
126
|
+
if (runtimeMode === 'feature-dev') {
|
|
127
|
+
return 'dev-mode';
|
|
128
|
+
}
|
|
129
|
+
if (dialogueProfile === 'system-maintainer' || executionMode === 'apply') {
|
|
130
|
+
return 'ops-mode';
|
|
131
|
+
}
|
|
132
|
+
return 'user-mode';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function applyPresetDefaults(options = {}, explicitKeys = new Set(), preset = null) {
|
|
136
|
+
if (!preset) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!explicitKeys.has('executionMode') && preset.execution_mode) {
|
|
141
|
+
options.executionMode = preset.execution_mode;
|
|
142
|
+
}
|
|
143
|
+
if (!explicitKeys.has('dialogueProfile') && preset.dialogue_profile) {
|
|
144
|
+
options.dialogueProfile = preset.dialogue_profile;
|
|
145
|
+
}
|
|
146
|
+
if (!explicitKeys.has('uiMode') && preset.ui_mode) {
|
|
147
|
+
options.uiMode = preset.ui_mode;
|
|
148
|
+
}
|
|
149
|
+
if (!explicitKeys.has('runtimeMode') && preset.runtime_mode) {
|
|
150
|
+
options.runtimeMode = preset.runtime_mode;
|
|
151
|
+
}
|
|
152
|
+
if (!explicitKeys.has('runtimeEnvironment') && preset.runtime_environment) {
|
|
153
|
+
options.runtimeEnvironment = preset.runtime_environment;
|
|
154
|
+
}
|
|
155
|
+
if (!explicitKeys.has('autoExecuteLowRisk') && typeof preset.auto_execute_low_risk === 'boolean') {
|
|
156
|
+
options.autoExecuteLowRisk = preset.auto_execute_low_risk;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function collectPresetConflicts(options = {}, preset = null) {
|
|
161
|
+
if (!preset) {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const checks = [
|
|
166
|
+
{ key: 'execution_mode', actual: `${options.executionMode || ''}`.trim().toLowerCase(), expected: preset.execution_mode },
|
|
167
|
+
{ key: 'dialogue_profile', actual: `${options.dialogueProfile || ''}`.trim().toLowerCase(), expected: preset.dialogue_profile },
|
|
168
|
+
{ key: 'ui_mode', actual: `${options.uiMode || ''}`.trim().toLowerCase(), expected: preset.ui_mode },
|
|
169
|
+
{ key: 'runtime_mode', actual: `${options.runtimeMode || ''}`.trim().toLowerCase(), expected: preset.runtime_mode },
|
|
170
|
+
{ key: 'runtime_environment', actual: `${options.runtimeEnvironment || ''}`.trim().toLowerCase(), expected: preset.runtime_environment }
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
return checks
|
|
174
|
+
.filter(item => item.expected && item.actual !== item.expected)
|
|
175
|
+
.map(item => ({
|
|
176
|
+
key: item.key,
|
|
177
|
+
expected: item.expected,
|
|
178
|
+
actual: item.actual || '(empty)'
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function buildAlignmentError(mode, conflicts = []) {
|
|
183
|
+
const summary = conflicts
|
|
184
|
+
.map(item => `${item.key}: expected ${item.expected}, got ${item.actual}`)
|
|
185
|
+
.join('; ');
|
|
186
|
+
return `--business-mode ${mode} conflicts with explicit options (${summary}). Use --allow-mode-override to continue.`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function applyBusinessModePolicy(options = {}, explicitKeys = new Set(), cwd = process.cwd()) {
|
|
190
|
+
const policyInfo = loadBusinessModePolicy({
|
|
191
|
+
cwd,
|
|
192
|
+
policyPath: options.businessModePolicy || DEFAULT_BUSINESS_MODE_POLICY
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const normalizedInputMode = normalizeBusinessMode(options.businessMode);
|
|
196
|
+
const fallbackMode = policyInfo.policy.defaults.mode && BUSINESS_MODES.has(policyInfo.policy.defaults.mode)
|
|
197
|
+
? policyInfo.policy.defaults.mode
|
|
198
|
+
: null;
|
|
199
|
+
const resolvedMode = normalizedInputMode || fallbackMode || inferBusinessMode(options);
|
|
200
|
+
const preset = policyInfo.policy.modes[resolvedMode] || null;
|
|
201
|
+
const modeExplicitlyProvided = normalizedInputMode != null;
|
|
202
|
+
const allowModeOverride = options.allowModeOverride === true;
|
|
203
|
+
const enforceAlignment = policyInfo.policy.defaults.enforce_alignment === true;
|
|
204
|
+
|
|
205
|
+
if (modeExplicitlyProvided) {
|
|
206
|
+
applyPresetDefaults(options, explicitKeys, preset);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const conflicts = modeExplicitlyProvided ? collectPresetConflicts(options, preset) : [];
|
|
210
|
+
if (modeExplicitlyProvided && enforceAlignment && !allowModeOverride && conflicts.length > 0) {
|
|
211
|
+
throw new Error(buildAlignmentError(resolvedMode, conflicts));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
options.businessMode = resolvedMode;
|
|
215
|
+
options.businessModePolicy = options.businessModePolicy || DEFAULT_BUSINESS_MODE_POLICY;
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
business_mode: resolvedMode,
|
|
219
|
+
mode_explicit: modeExplicitlyProvided,
|
|
220
|
+
allow_mode_override: allowModeOverride,
|
|
221
|
+
policy_path: policyInfo.policy_path,
|
|
222
|
+
policy_source: policyInfo.policy_source,
|
|
223
|
+
preset,
|
|
224
|
+
conflicts
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
module.exports = {
|
|
229
|
+
DEFAULT_BUSINESS_MODE_POLICY,
|
|
230
|
+
BUSINESS_MODES,
|
|
231
|
+
BUILTIN_POLICY,
|
|
232
|
+
normalizeBusinessMode,
|
|
233
|
+
normalizePolicy,
|
|
234
|
+
loadBusinessModePolicy,
|
|
235
|
+
inferBusinessMode,
|
|
236
|
+
applyPresetDefaults,
|
|
237
|
+
collectPresetConflicts,
|
|
238
|
+
buildAlignmentError,
|
|
239
|
+
applyBusinessModePolicy
|
|
240
|
+
};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { SteeringContract, normalizeToolName } = require('./steering-contract');
|
|
4
|
+
|
|
5
|
+
const SESSION_SCHEMA_VERSION = '1.0';
|
|
6
|
+
const SESSION_DIR = path.join('.sce', 'sessions');
|
|
7
|
+
|
|
8
|
+
function toRelativePosix(workspaceRoot, absolutePath) {
|
|
9
|
+
return path.relative(workspaceRoot, absolutePath).replace(/\\/g, '/');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function safeSessionId(value) {
|
|
13
|
+
return `${value || ''}`.trim().replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-+|-+$/g, '');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function generateSessionId() {
|
|
17
|
+
const now = new Date();
|
|
18
|
+
const yyyy = now.getUTCFullYear();
|
|
19
|
+
const mm = `${now.getUTCMonth() + 1}`.padStart(2, '0');
|
|
20
|
+
const dd = `${now.getUTCDate()}`.padStart(2, '0');
|
|
21
|
+
const hh = `${now.getUTCHours()}`.padStart(2, '0');
|
|
22
|
+
const mi = `${now.getUTCMinutes()}`.padStart(2, '0');
|
|
23
|
+
const ss = `${now.getUTCSeconds()}`.padStart(2, '0');
|
|
24
|
+
const rand = Math.random().toString(36).slice(2, 8);
|
|
25
|
+
return `sess-${yyyy}${mm}${dd}-${hh}${mi}${ss}-${rand}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class SessionStore {
|
|
29
|
+
constructor(workspaceRoot, steeringContract = null) {
|
|
30
|
+
this._workspaceRoot = workspaceRoot;
|
|
31
|
+
this._sessionsDir = path.join(workspaceRoot, SESSION_DIR);
|
|
32
|
+
this._steeringContract = steeringContract || new SteeringContract(workspaceRoot);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async startSession(options = {}) {
|
|
36
|
+
const tool = normalizeToolName(options.tool || 'generic');
|
|
37
|
+
const agentVersion = options.agentVersion ? `${options.agentVersion}` : null;
|
|
38
|
+
const objective = `${options.objective || ''}`.trim();
|
|
39
|
+
const requestedId = safeSessionId(options.sessionId);
|
|
40
|
+
const sessionId = requestedId || generateSessionId();
|
|
41
|
+
const now = new Date().toISOString();
|
|
42
|
+
|
|
43
|
+
await this._steeringContract.ensureContract();
|
|
44
|
+
const steeringPayload = await this._steeringContract.buildCompilePayload(tool, agentVersion);
|
|
45
|
+
await fs.ensureDir(this._sessionsDir);
|
|
46
|
+
|
|
47
|
+
const sessionPath = this._sessionPath(sessionId);
|
|
48
|
+
if (await fs.pathExists(sessionPath)) {
|
|
49
|
+
throw new Error(`Session already exists: ${sessionId}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const session = {
|
|
53
|
+
schema_version: SESSION_SCHEMA_VERSION,
|
|
54
|
+
session_id: sessionId,
|
|
55
|
+
tool,
|
|
56
|
+
agent_version: agentVersion,
|
|
57
|
+
objective,
|
|
58
|
+
status: 'active',
|
|
59
|
+
started_at: now,
|
|
60
|
+
updated_at: now,
|
|
61
|
+
workspace: {
|
|
62
|
+
root: this._workspaceRoot,
|
|
63
|
+
},
|
|
64
|
+
steering: {
|
|
65
|
+
manifest_path: toRelativePosix(this._workspaceRoot, this._steeringContract.manifestPath),
|
|
66
|
+
source_mode: steeringPayload.source_mode,
|
|
67
|
+
compatibility: steeringPayload.compatibility,
|
|
68
|
+
},
|
|
69
|
+
snapshots: [],
|
|
70
|
+
timeline: [
|
|
71
|
+
{
|
|
72
|
+
at: now,
|
|
73
|
+
event: 'session_started',
|
|
74
|
+
detail: {
|
|
75
|
+
tool,
|
|
76
|
+
agent_version: agentVersion,
|
|
77
|
+
objective,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
await this._writeSession(sessionId, session);
|
|
84
|
+
return session;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async resumeSession(sessionRef = 'latest', options = {}) {
|
|
88
|
+
const { sessionId, session } = await this._resolveSession(sessionRef);
|
|
89
|
+
const now = new Date().toISOString();
|
|
90
|
+
const status = `${options.status || 'active'}`.trim() || 'active';
|
|
91
|
+
|
|
92
|
+
session.status = status;
|
|
93
|
+
session.updated_at = now;
|
|
94
|
+
session.timeline = Array.isArray(session.timeline) ? session.timeline : [];
|
|
95
|
+
session.timeline.push({
|
|
96
|
+
at: now,
|
|
97
|
+
event: 'session_resumed',
|
|
98
|
+
detail: { status },
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await this._writeSession(sessionId, session);
|
|
102
|
+
return session;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async snapshotSession(sessionRef = 'latest', options = {}) {
|
|
106
|
+
const { sessionId, session } = await this._resolveSession(sessionRef);
|
|
107
|
+
const now = new Date().toISOString();
|
|
108
|
+
const summary = `${options.summary || ''}`.trim();
|
|
109
|
+
const status = options.status ? `${options.status}`.trim() : session.status;
|
|
110
|
+
const payload = options.payload == null ? null : options.payload;
|
|
111
|
+
|
|
112
|
+
session.snapshots = Array.isArray(session.snapshots) ? session.snapshots : [];
|
|
113
|
+
session.timeline = Array.isArray(session.timeline) ? session.timeline : [];
|
|
114
|
+
|
|
115
|
+
const snapshot = {
|
|
116
|
+
snapshot_id: `snap-${session.snapshots.length + 1}`,
|
|
117
|
+
captured_at: now,
|
|
118
|
+
status,
|
|
119
|
+
summary,
|
|
120
|
+
payload,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
session.snapshots.push(snapshot);
|
|
124
|
+
session.status = status;
|
|
125
|
+
session.updated_at = now;
|
|
126
|
+
session.timeline.push({
|
|
127
|
+
at: now,
|
|
128
|
+
event: 'snapshot_created',
|
|
129
|
+
detail: {
|
|
130
|
+
snapshot_id: snapshot.snapshot_id,
|
|
131
|
+
status,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
await this._writeSession(sessionId, session);
|
|
136
|
+
return session;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async getSession(sessionRef = 'latest') {
|
|
140
|
+
const resolved = await this._resolveSession(sessionRef);
|
|
141
|
+
return resolved.session;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async listSessions() {
|
|
145
|
+
if (!await fs.pathExists(this._sessionsDir)) {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
const entries = await fs.readdir(this._sessionsDir);
|
|
149
|
+
const records = [];
|
|
150
|
+
for (const entry of entries) {
|
|
151
|
+
if (!entry.endsWith('.json')) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const sessionId = entry.slice(0, -'.json'.length);
|
|
155
|
+
try {
|
|
156
|
+
const session = await fs.readJson(this._sessionPath(sessionId));
|
|
157
|
+
records.push(session);
|
|
158
|
+
} catch (_error) {
|
|
159
|
+
// Ignore unreadable entries.
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
records.sort((a, b) => {
|
|
163
|
+
const left = Date.parse(a.updated_at || a.started_at || 0);
|
|
164
|
+
const right = Date.parse(b.updated_at || b.started_at || 0);
|
|
165
|
+
return right - left;
|
|
166
|
+
});
|
|
167
|
+
return records;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async _resolveSession(sessionRef) {
|
|
171
|
+
const ref = `${sessionRef || 'latest'}`.trim();
|
|
172
|
+
if (ref === 'latest') {
|
|
173
|
+
const sessions = await this.listSessions();
|
|
174
|
+
if (sessions.length === 0) {
|
|
175
|
+
throw new Error('No session found');
|
|
176
|
+
}
|
|
177
|
+
const session = sessions[0];
|
|
178
|
+
return { sessionId: session.session_id, session };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const sessionId = safeSessionId(ref);
|
|
182
|
+
if (!sessionId) {
|
|
183
|
+
throw new Error(`Invalid session id: ${ref}`);
|
|
184
|
+
}
|
|
185
|
+
const sessionPath = this._sessionPath(sessionId);
|
|
186
|
+
if (!await fs.pathExists(sessionPath)) {
|
|
187
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
188
|
+
}
|
|
189
|
+
const session = await fs.readJson(sessionPath);
|
|
190
|
+
return { sessionId, session };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async _writeSession(sessionId, session) {
|
|
194
|
+
await fs.ensureDir(this._sessionsDir);
|
|
195
|
+
await fs.writeJson(this._sessionPath(sessionId), session, { spaces: 2 });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
_sessionPath(sessionId) {
|
|
199
|
+
return path.join(this._sessionsDir, `${sessionId}.json`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
module.exports = {
|
|
204
|
+
SessionStore,
|
|
205
|
+
SESSION_SCHEMA_VERSION,
|
|
206
|
+
SESSION_DIR,
|
|
207
|
+
};
|