scene-capability-engine 3.3.22 → 3.3.24

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.
@@ -11,6 +11,7 @@ const { ContextCollector } = require('../spec/bootstrap/context-collector');
11
11
  const { QuestionnaireEngine } = require('../spec/bootstrap/questionnaire-engine');
12
12
  const { DraftGenerator } = require('../spec/bootstrap/draft-generator');
13
13
  const { TraceEmitter } = require('../spec/bootstrap/trace-emitter');
14
+ const { ensureSpecDomainArtifacts } = require('../spec/domain-modeling');
14
15
  const { SessionStore } = require('../runtime/session-store');
15
16
  const { resolveSpecSceneBinding } = require('../runtime/scene-session-binding');
16
17
  const { bindMultiSpecSceneSession } = require('../runtime/multi-spec-scene-session');
@@ -114,6 +115,14 @@ async function runSpecBootstrap(options = {}, dependencies = {}) {
114
115
  await fs.writeFile(files.tasks, draft.tasks, 'utf8');
115
116
  }
116
117
 
118
+ const domainArtifacts = await ensureSpecDomainArtifacts(projectPath, specName, {
119
+ dryRun: !!options.dryRun,
120
+ sceneId: sceneBinding.scene_id,
121
+ problemStatement: answers.problemStatement,
122
+ primaryFlow: answers.primaryFlow,
123
+ verificationPlan: answers.verificationPlan
124
+ });
125
+
117
126
  const result = {
118
127
  success: true,
119
128
  specName,
@@ -122,7 +131,10 @@ async function runSpecBootstrap(options = {}, dependencies = {}) {
122
131
  files: {
123
132
  requirements: path.relative(projectPath, files.requirements),
124
133
  design: path.relative(projectPath, files.design),
125
- tasks: path.relative(projectPath, files.tasks)
134
+ tasks: path.relative(projectPath, files.tasks),
135
+ domain_map: path.relative(projectPath, domainArtifacts.paths.domain_map),
136
+ scene_spec: path.relative(projectPath, domainArtifacts.paths.scene_spec),
137
+ domain_chain: path.relative(projectPath, domainArtifacts.paths.domain_chain)
126
138
  },
127
139
  trace: {
128
140
  template: options.template || 'default',
@@ -141,7 +153,10 @@ async function runSpecBootstrap(options = {}, dependencies = {}) {
141
153
  preview: {
142
154
  requirements: draft.requirements,
143
155
  design: draft.design,
144
- tasks: draft.tasks
156
+ tasks: draft.tasks,
157
+ domain_map: domainArtifacts.preview.domain_map,
158
+ scene_spec: domainArtifacts.preview.scene_spec,
159
+ domain_chain: domainArtifacts.preview.domain_chain
145
160
  },
146
161
  scene_session: sceneBinding
147
162
  ? {
@@ -0,0 +1,217 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const {
5
+ ensureSpecDomainArtifacts,
6
+ validateSpecDomainArtifacts
7
+ } = require('../spec/domain-modeling');
8
+
9
+ function normalizeText(value) {
10
+ if (typeof value !== 'string') {
11
+ return '';
12
+ }
13
+ return value.trim();
14
+ }
15
+
16
+ function resolveSpecId(options = {}) {
17
+ return normalizeText(options.spec || options.name);
18
+ }
19
+
20
+ async function assertSpecExists(projectPath, specId, fileSystem = fs) {
21
+ const specPath = path.join(projectPath, '.sce', 'specs', specId);
22
+ if (!await fileSystem.pathExists(specPath)) {
23
+ throw new Error(`Spec not found: ${specId}`);
24
+ }
25
+ return specPath;
26
+ }
27
+
28
+ async function runSpecDomainInitCommand(options = {}, dependencies = {}) {
29
+ const projectPath = dependencies.projectPath || process.cwd();
30
+ const fileSystem = dependencies.fileSystem || fs;
31
+ const specId = resolveSpecId(options);
32
+ if (!specId) {
33
+ throw new Error('--spec is required');
34
+ }
35
+ await assertSpecExists(projectPath, specId, fileSystem);
36
+
37
+ const result = await ensureSpecDomainArtifacts(projectPath, specId, {
38
+ fileSystem,
39
+ dryRun: options.dryRun === true,
40
+ force: false,
41
+ sceneId: options.scene,
42
+ problemStatement: options.problem,
43
+ primaryFlow: options.primaryFlow,
44
+ verificationPlan: options.verificationPlan
45
+ });
46
+
47
+ const payload = {
48
+ mode: 'spec-domain-init',
49
+ spec_id: specId,
50
+ dry_run: options.dryRun === true,
51
+ created: result.created,
52
+ files: result.paths
53
+ };
54
+
55
+ if (options.json) {
56
+ console.log(JSON.stringify(payload, null, 2));
57
+ } else if (!options.silent) {
58
+ console.log(chalk.green('✓ Spec domain artifacts initialized'));
59
+ console.log(chalk.gray(` spec: ${specId}`));
60
+ }
61
+
62
+ return payload;
63
+ }
64
+
65
+ async function runSpecDomainRefreshCommand(options = {}, dependencies = {}) {
66
+ const projectPath = dependencies.projectPath || process.cwd();
67
+ const fileSystem = dependencies.fileSystem || fs;
68
+ const specId = resolveSpecId(options);
69
+ if (!specId) {
70
+ throw new Error('--spec is required');
71
+ }
72
+ await assertSpecExists(projectPath, specId, fileSystem);
73
+
74
+ const result = await ensureSpecDomainArtifacts(projectPath, specId, {
75
+ fileSystem,
76
+ dryRun: options.dryRun === true,
77
+ force: true,
78
+ sceneId: options.scene,
79
+ problemStatement: options.problem,
80
+ primaryFlow: options.primaryFlow,
81
+ verificationPlan: options.verificationPlan
82
+ });
83
+
84
+ const payload = {
85
+ mode: 'spec-domain-refresh',
86
+ spec_id: specId,
87
+ dry_run: options.dryRun === true,
88
+ refreshed: result.created,
89
+ files: result.paths
90
+ };
91
+
92
+ if (options.json) {
93
+ console.log(JSON.stringify(payload, null, 2));
94
+ } else if (!options.silent) {
95
+ console.log(chalk.green('✓ Spec domain artifacts refreshed'));
96
+ console.log(chalk.gray(` spec: ${specId}`));
97
+ }
98
+
99
+ return payload;
100
+ }
101
+
102
+ async function runSpecDomainValidateCommand(options = {}, dependencies = {}) {
103
+ const projectPath = dependencies.projectPath || process.cwd();
104
+ const fileSystem = dependencies.fileSystem || fs;
105
+ const specId = resolveSpecId(options);
106
+ if (!specId) {
107
+ throw new Error('--spec is required');
108
+ }
109
+ await assertSpecExists(projectPath, specId, fileSystem);
110
+
111
+ const validation = await validateSpecDomainArtifacts(projectPath, specId, fileSystem);
112
+ const payload = {
113
+ mode: 'spec-domain-validate',
114
+ spec_id: specId,
115
+ passed: validation.passed,
116
+ ratio: validation.ratio,
117
+ details: validation.details,
118
+ warnings: validation.warnings
119
+ };
120
+
121
+ if (options.failOnError && !validation.passed) {
122
+ throw new Error(`spec domain validation failed: ${validation.warnings.join('; ')}`);
123
+ }
124
+
125
+ if (options.json) {
126
+ console.log(JSON.stringify(payload, null, 2));
127
+ } else if (!options.silent) {
128
+ if (validation.passed) {
129
+ console.log(chalk.green('✓ Spec domain validation passed'));
130
+ } else {
131
+ console.log(chalk.red('✗ Spec domain validation failed'));
132
+ validation.warnings.forEach((message) => {
133
+ console.log(chalk.gray(` - ${message}`));
134
+ });
135
+ }
136
+ }
137
+
138
+ return payload;
139
+ }
140
+
141
+ function registerSpecDomainCommand(program) {
142
+ const specDomain = program
143
+ .command('spec-domain')
144
+ .description('Manage problem-domain modeling artifacts (use: sce spec domain)');
145
+
146
+ specDomain
147
+ .command('init')
148
+ .description('Create missing problem-domain artifacts for a Spec')
149
+ .requiredOption('--spec <name>', 'Spec identifier')
150
+ .option('--scene <scene-id>', 'Scene id used in generated chain/model')
151
+ .option('--problem <text>', 'Problem statement seed')
152
+ .option('--primary-flow <text>', 'Primary flow seed')
153
+ .option('--verification-plan <text>', 'Verification plan seed')
154
+ .option('--dry-run', 'Preview output without writing files')
155
+ .option('--json', 'Output machine-readable JSON')
156
+ .action(async (options) => {
157
+ try {
158
+ await runSpecDomainInitCommand(options);
159
+ } catch (error) {
160
+ if (options.json) {
161
+ console.log(JSON.stringify({ success: false, error: error.message }, null, 2));
162
+ } else {
163
+ console.error(chalk.red('❌ spec-domain init failed:'), error.message);
164
+ }
165
+ process.exit(1);
166
+ }
167
+ });
168
+
169
+ specDomain
170
+ .command('refresh')
171
+ .description('Force-refresh problem-domain artifacts for a Spec')
172
+ .requiredOption('--spec <name>', 'Spec identifier')
173
+ .option('--scene <scene-id>', 'Scene id used in generated chain/model')
174
+ .option('--problem <text>', 'Problem statement seed')
175
+ .option('--primary-flow <text>', 'Primary flow seed')
176
+ .option('--verification-plan <text>', 'Verification plan seed')
177
+ .option('--dry-run', 'Preview output without writing files')
178
+ .option('--json', 'Output machine-readable JSON')
179
+ .action(async (options) => {
180
+ try {
181
+ await runSpecDomainRefreshCommand(options);
182
+ } catch (error) {
183
+ if (options.json) {
184
+ console.log(JSON.stringify({ success: false, error: error.message }, null, 2));
185
+ } else {
186
+ console.error(chalk.red('❌ spec-domain refresh failed:'), error.message);
187
+ }
188
+ process.exit(1);
189
+ }
190
+ });
191
+
192
+ specDomain
193
+ .command('validate')
194
+ .description('Validate problem-domain artifacts for a Spec')
195
+ .requiredOption('--spec <name>', 'Spec identifier')
196
+ .option('--fail-on-error', 'Exit non-zero when validation fails')
197
+ .option('--json', 'Output machine-readable JSON')
198
+ .action(async (options) => {
199
+ try {
200
+ await runSpecDomainValidateCommand(options);
201
+ } catch (error) {
202
+ if (options.json) {
203
+ console.log(JSON.stringify({ success: false, error: error.message }, null, 2));
204
+ } else {
205
+ console.error(chalk.red('❌ spec-domain validate failed:'), error.message);
206
+ }
207
+ process.exit(1);
208
+ }
209
+ });
210
+ }
211
+
212
+ module.exports = {
213
+ runSpecDomainInitCommand,
214
+ runSpecDomainRefreshCommand,
215
+ runSpecDomainValidateCommand,
216
+ registerSpecDomainCommand
217
+ };