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.
Files changed (241) hide show
  1. package/CHANGELOG.md +130 -78
  2. package/README.md +6 -6
  3. package/README.zh.md +6 -6
  4. package/bin/scene-capability-engine.js +129 -7
  5. package/docs/331-poc-adaptation-roadmap.md +3 -3
  6. package/docs/331-poc-dual-track-integration-guide.md +8 -8
  7. package/docs/331-poc-weekly-delivery-checklist.md +6 -6
  8. package/docs/README.md +4 -0
  9. package/docs/adopt-migration-guide.md +13 -13
  10. package/docs/adoption-guide.md +28 -28
  11. package/docs/agent-hooks-analysis.md +10 -10
  12. package/docs/architecture.md +13 -13
  13. package/docs/articles/ai-driven-development-philosophy-and-practice.en.md +3 -3
  14. package/docs/articles/ai-driven-development-philosophy-and-practice.md +3 -3
  15. package/docs/autonomous-control-guide.md +35 -35
  16. package/docs/command-reference.md +192 -153
  17. package/docs/cross-tool-guide.md +7 -7
  18. package/docs/developer-guide.md +8 -8
  19. package/docs/document-governance.md +15 -15
  20. package/docs/environment-management-guide.md +6 -6
  21. package/docs/examples/add-export-command/design.md +1 -1
  22. package/docs/faq.md +13 -13
  23. package/docs/handoff-profile-integration-guide.md +3 -3
  24. package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.json +7 -7
  25. package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.md +1 -1
  26. package/docs/integration-modes.md +12 -12
  27. package/docs/integration-philosophy.md +11 -11
  28. package/docs/interactive-customization/331-poc-sce-integration-checklist.md +24 -24
  29. package/docs/interactive-customization/README.md +43 -43
  30. package/docs/interactive-customization/business-mode-policy-baseline.json +33 -0
  31. package/docs/interactive-customization/dual-ui-mode-integration-guide.md +1 -1
  32. package/docs/interactive-customization/moqui-adapter-interface.md +2 -2
  33. package/docs/interactive-customization/moqui-copilot-integration-guide.md +1 -1
  34. package/docs/interactive-customization/moqui-interactive-template-playbook.md +4 -4
  35. package/docs/interactive-customization/phase-acceptance-evidence.md +2 -2
  36. package/docs/knowledge-management-guide.md +6 -6
  37. package/docs/manual-workflows-guide.md +4 -4
  38. package/docs/moqui-capability-matrix.md +3 -3
  39. package/docs/moqui-standard-rebuild-guide.md +8 -8
  40. package/docs/moqui-template-core-library-playbook.md +27 -27
  41. package/docs/multi-agent-coordination-guide.md +19 -19
  42. package/docs/multi-repo-management-guide.md +17 -17
  43. package/docs/quick-start-with-ai-tools.md +7 -7
  44. package/docs/quick-start.md +2 -2
  45. package/docs/release-checklist.md +4 -4
  46. package/docs/sce-business-mode-map.md +103 -0
  47. package/docs/security-governance-default-baseline.md +12 -12
  48. package/docs/spec-collaboration-guide.md +3 -3
  49. package/docs/spec-locking-guide.md +2 -2
  50. package/docs/spec-workflow.md +3 -3
  51. package/docs/starter-kit/README.md +4 -4
  52. package/docs/starter-kit/handoff-manifest.starter.json +2 -2
  53. package/docs/starter-kit/release.workflow.sample.yml +1 -1
  54. package/docs/steering-strategy-guide.md +15 -15
  55. package/docs/team-collaboration-guide.md +69 -69
  56. package/docs/testing-strategy.md +2 -2
  57. package/docs/tools/claude-guide.md +14 -4
  58. package/docs/tools/cursor-guide.md +14 -14
  59. package/docs/tools/generic-guide.md +9 -9
  60. package/docs/tools/kiro-guide.md +4 -4
  61. package/docs/tools/vscode-guide.md +13 -13
  62. package/docs/tools/windsurf-guide.md +6 -6
  63. package/docs/troubleshooting.md +22 -22
  64. package/docs/upgrade-guide.md +8 -8
  65. package/docs/value-observability-guide.md +3 -3
  66. package/docs/zh/README.md +6 -0
  67. package/docs/zh/quick-start.md +15 -15
  68. package/docs/zh/release-checklist.md +3 -3
  69. package/docs/zh/tools/claude-guide.md +16 -6
  70. package/docs/zh/tools/cursor-guide.md +11 -11
  71. package/docs/zh/tools/generic-guide.md +13 -13
  72. package/docs/zh/tools/kiro-guide.md +2 -2
  73. package/docs/zh/tools/vscode-guide.md +11 -11
  74. package/docs/zh/tools/windsurf-guide.md +11 -11
  75. package/docs/zh/value-observability-guide.md +3 -3
  76. package/lib/adoption/adoption-logger.js +1 -1
  77. package/lib/adoption/adoption-strategy.js +28 -28
  78. package/lib/adoption/backup-manager.js +3 -3
  79. package/lib/adoption/conflict-resolver.js +2 -2
  80. package/lib/adoption/detection-engine.js +8 -8
  81. package/lib/adoption/error-formatter.js +4 -4
  82. package/lib/adoption/file-classifier.js +6 -6
  83. package/lib/adoption/progress-reporter.js +1 -1
  84. package/lib/adoption/smart-orchestrator.js +10 -10
  85. package/lib/adoption/strategy-selector.js +6 -6
  86. package/lib/adoption/summary-generator.js +1 -1
  87. package/lib/adoption/template-sync.js +8 -8
  88. package/lib/auto/autonomous-engine.js +7 -7
  89. package/lib/auto/checkpoint-manager.js +1 -1
  90. package/lib/auto/close-loop-runner.js +12 -12
  91. package/lib/auto/error-recovery-manager.js +1 -1
  92. package/lib/auto/goal-decomposer.js +1 -1
  93. package/lib/auto/moqui-recovery-sequence.js +2 -2
  94. package/lib/auto/progress-tracker.js +1 -1
  95. package/lib/auto/state-manager.js +1 -1
  96. package/lib/backup/backup-system.js +10 -10
  97. package/lib/backup/selective-backup.js +4 -4
  98. package/lib/collab/agent-registry.js +2 -2
  99. package/lib/collab/contract-manager.js +1 -1
  100. package/lib/collab/coordinator.js +2 -2
  101. package/lib/collab/dependency-manager.js +1 -1
  102. package/lib/collab/integration-manager.js +1 -1
  103. package/lib/collab/metadata-manager.js +1 -1
  104. package/lib/collab/multi-agent-config.js +2 -2
  105. package/lib/collab/spec-lifecycle-manager.js +2 -2
  106. package/lib/collab/visualizer.js +1 -1
  107. package/lib/commands/adopt.js +6 -6
  108. package/lib/commands/auto.js +56 -56
  109. package/lib/commands/collab.js +2 -2
  110. package/lib/commands/docs.js +3 -3
  111. package/lib/commands/doctor.js +1 -1
  112. package/lib/commands/knowledge.js +2 -2
  113. package/lib/commands/lock.js +1 -1
  114. package/lib/commands/ops.js +1 -1
  115. package/lib/commands/orchestrate.js +3 -3
  116. package/lib/commands/rollback.js +1 -1
  117. package/lib/commands/scene.js +135 -93
  118. package/lib/commands/session.js +139 -0
  119. package/lib/commands/spec-bootstrap.js +1 -1
  120. package/lib/commands/spec-gate.js +2 -2
  121. package/lib/commands/spec-pipeline.js +1 -1
  122. package/lib/commands/status.js +4 -4
  123. package/lib/commands/steering.js +119 -0
  124. package/lib/commands/value.js +1 -1
  125. package/lib/commands/watch.js +9 -9
  126. package/lib/commands/workspace-multi.js +1 -1
  127. package/lib/context/context-exporter.js +5 -7
  128. package/lib/context/prompt-generator.js +2 -2
  129. package/lib/environment/backup-system.js +1 -1
  130. package/lib/environment/environment-manager.js +2 -2
  131. package/lib/gitignore/gitignore-backup.js +3 -3
  132. package/lib/gitignore/gitignore-detector.js +13 -13
  133. package/lib/gitignore/gitignore-integration.js +3 -3
  134. package/lib/gitignore/gitignore-transformer.js +4 -4
  135. package/lib/gitignore/layered-rules-template.js +16 -16
  136. package/lib/governance/config-manager.js +1 -1
  137. package/lib/governance/doc-reference-checker.js +4 -4
  138. package/lib/governance/execution-logger.js +1 -1
  139. package/lib/governance/file-scanner.js +3 -3
  140. package/lib/interactive-customization/moqui-interactive-adapter.js +2 -2
  141. package/lib/knowledge/knowledge-manager.js +1 -1
  142. package/lib/lock/lock-manager.js +2 -2
  143. package/lib/lock/steering-file-lock.js +5 -5
  144. package/lib/lock/task-lock-manager.js +3 -3
  145. package/lib/operations/audit-logger.js +1 -1
  146. package/lib/operations/feedback-manager.js +1 -1
  147. package/lib/operations/operations-manager.js +3 -3
  148. package/lib/operations/permission-manager.js +2 -2
  149. package/lib/operations/template-loader.js +1 -1
  150. package/lib/orchestrator/agent-spawner.js +27 -2
  151. package/lib/orchestrator/bootstrap-prompt-builder.js +6 -6
  152. package/lib/orchestrator/orchestration-engine.js +1 -1
  153. package/lib/orchestrator/orchestrator-config.js +2 -2
  154. package/lib/repo/config-manager.js +3 -3
  155. package/lib/repo/handlers/init-handler.js +1 -1
  156. package/lib/repo/repo-manager.js +2 -2
  157. package/lib/runtime/business-mode-resolver.js +240 -0
  158. package/lib/runtime/session-store.js +207 -0
  159. package/lib/runtime/steering-contract.js +338 -0
  160. package/lib/scene-runtime/audit-emitter.js +1 -1
  161. package/lib/scene-runtime/binding-plugin-loader.js +3 -3
  162. package/lib/scene-runtime/eval-bridge.js +1 -1
  163. package/lib/scene-runtime/index.js +1 -1
  164. package/lib/scene-runtime/moqui-extractor.js +1 -1
  165. package/lib/scene-runtime/plan-compiler.js +1 -1
  166. package/lib/scene-runtime/policy-gate.js +1 -1
  167. package/lib/scene-runtime/runtime-executor.js +1 -1
  168. package/lib/scene-runtime/scene-loader.js +1 -1
  169. package/lib/spec/bootstrap/context-collector.js +1 -1
  170. package/lib/spec/pipeline/stage-adapters.js +3 -3
  171. package/lib/spec/pipeline/state-store.js +1 -1
  172. package/lib/spec-gate/policy/policy-loader.js +1 -1
  173. package/lib/spec-gate/rules/default-rules.js +6 -6
  174. package/lib/steering/adoption-config.js +1 -1
  175. package/lib/steering/compliance-error-reporter.js +3 -3
  176. package/lib/steering/context-sync-manager.js +2 -2
  177. package/lib/steering/index.js +1 -1
  178. package/lib/steering/spec-steering.js +2 -2
  179. package/lib/steering/steering-compliance-checker.js +1 -1
  180. package/lib/steering/steering-loader.js +4 -5
  181. package/lib/steering/steering-manager.js +4 -4
  182. package/lib/task/task-claimer.js +5 -5
  183. package/lib/task/task-status-store.js +2 -2
  184. package/lib/templates/content-generalizer.js +1 -1
  185. package/lib/templates/spec-reader.js +2 -2
  186. package/lib/templates/template-creator.js +1 -1
  187. package/lib/templates/template-exporter.js +3 -3
  188. package/lib/templates/template-manager.js +1 -1
  189. package/lib/upgrade/migration-engine.js +3 -3
  190. package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +1 -1
  191. package/lib/utils/file-diff.js +6 -6
  192. package/lib/utils/tool-detector.js +10 -10
  193. package/lib/utils/validation.js +5 -5
  194. package/lib/value/metric-contract-loader.js +1 -1
  195. package/lib/version/version-manager.js +1 -1
  196. package/lib/watch/execution-logger.js +1 -1
  197. package/lib/watch/presets.js +8 -8
  198. package/lib/watch/watch-manager.js +2 -2
  199. package/lib/workspace/legacy-kiro-migrator.js +275 -0
  200. package/lib/workspace/multi/workspace-context-resolver.js +2 -2
  201. package/lib/workspace/multi/workspace-registry.js +2 -2
  202. package/lib/workspace/multi/workspace-state-manager.js +3 -3
  203. package/lib/workspace/workspace-manager.js +1 -1
  204. package/lib/workspace/workspace-sync.js +2 -2
  205. package/locales/en.json +4 -4
  206. package/locales/zh.json +4 -4
  207. package/package.json +9 -9
  208. package/template/{.kiro → .sce}/README.md +15 -15
  209. package/template/{.kiro → .sce}/hooks/check-spec-on-create.kiro.hook +2 -2
  210. package/template/{.kiro → .sce}/steering/CORE_PRINCIPLES.md +4 -4
  211. package/template/{.kiro → .sce}/steering/CURRENT_CONTEXT.md +1 -1
  212. package/template/{.kiro → .sce}/steering/ENVIRONMENT.md +3 -3
  213. package/template/{.kiro → .sce}/tools/backup_manager.py +3 -3
  214. package/template/{.kiro → .sce}/tools/configuration_manager.py +1 -1
  215. package/template/README.md +12 -12
  216. /package/template/{.kiro → .sce}/hooks/run-tests-on-save.kiro.hook +0 -0
  217. /package/template/{.kiro → .sce}/hooks/sync-tasks-on-edit.kiro.hook +0 -0
  218. /package/template/{.kiro → .sce}/specs/SPEC_WORKFLOW_GUIDE.md +0 -0
  219. /package/template/{.kiro → .sce}/steering/RULES_GUIDE.md +0 -0
  220. /package/template/{.kiro → .sce}/templates/operations/default/change-impact.md +0 -0
  221. /package/template/{.kiro → .sce}/templates/operations/default/deployment.md +0 -0
  222. /package/template/{.kiro → .sce}/templates/operations/default/feedback-response.md +0 -0
  223. /package/template/{.kiro → .sce}/templates/operations/default/migration-plan.md +0 -0
  224. /package/template/{.kiro → .sce}/templates/operations/default/monitoring.md +0 -0
  225. /package/template/{.kiro → .sce}/templates/operations/default/operations.md +0 -0
  226. /package/template/{.kiro → .sce}/templates/operations/default/rollback.md +0 -0
  227. /package/template/{.kiro → .sce}/templates/operations/default/tools.yaml +0 -0
  228. /package/template/{.kiro → .sce}/templates/operations/default/troubleshooting.md +0 -0
  229. /package/template/{.kiro → .sce}/tools/document_evaluator.py +0 -0
  230. /package/template/{.kiro → .sce}/tools/enhancement_logger.py +0 -0
  231. /package/template/{.kiro → .sce}/tools/error_handler.py +0 -0
  232. /package/template/{.kiro → .sce}/tools/improvement_identifier.py +0 -0
  233. /package/template/{.kiro → .sce}/tools/modification_applicator.py +0 -0
  234. /package/template/{.kiro → .sce}/tools/quality_gate_enforcer.py +0 -0
  235. /package/template/{.kiro → .sce}/tools/quality_scorer.py +0 -0
  236. /package/template/{.kiro → .sce}/tools/report_generator.py +0 -0
  237. /package/template/{.kiro → .sce}/tools/ultrawork_enhancer.py +0 -0
  238. /package/template/{.kiro → .sce}/tools/ultrawork_enhancer_refactored.py +0 -0
  239. /package/template/{.kiro → .sce}/tools/ultrawork_enhancer_v2.py +0 -0
  240. /package/template/{.kiro → .sce}/tools/ultrawork_enhancer_v3.py +0 -0
  241. /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
+ };