@specverse/engines 6.0.13 → 6.0.14

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.
@@ -1145,6 +1145,158 @@ import type { ParserEngine } from '@specverse/types';`,
1145
1145
  process.exit(1);
1146
1146
  }`
1147
1147
  },
1148
+ "ai.analyse": {
1149
+ imports: `import { resolve, basename } from 'path';
1150
+ import { existsSync, mkdirSync, cpSync, statSync, readdirSync } from 'fs';`,
1151
+ handler: `// Resolve the absolute source dir.
1152
+ const userCwd = process.env.SPECVERSE_USER_CWD || process.cwd();
1153
+ const sourceAbs = resolve(userCwd, source);
1154
+ if (!existsSync(sourceAbs)) {
1155
+ console.error('Source dir not found: ' + sourceAbs);
1156
+ process.exit(1);
1157
+ }
1158
+
1159
+ // Default output: ./runs/analyse/<basename>/<date>_<label>/
1160
+ const { runAnalyse, buildRunFolder, caseRunPath, ensureSubdirs, inputDir, resolveProviderId } = await import('@specverse/engines/ai');
1161
+ const providerId = resolveProviderId();
1162
+ const modelId = process.env.SPECVERSE_AI_MODEL || 'default';
1163
+ const runFolder = buildRunFolder({
1164
+ prompt: 'analyse-v9',
1165
+ providerId,
1166
+ modelId,
1167
+ label: options.label,
1168
+ });
1169
+ const outputDir = options.output
1170
+ ? resolve(userCwd, options.output)
1171
+ : caseRunPath(userCwd, 'analyse', basename(sourceAbs), runFolder);
1172
+ ensureSubdirs(outputDir);
1173
+
1174
+ // Copy source into outputDir/input/ (excluding noisy indices) so the
1175
+ // run dir is self-contained.
1176
+ const inDir = inputDir(outputDir);
1177
+ const stat = statSync(sourceAbs);
1178
+ if (stat.isDirectory()) {
1179
+ if (existsSync(inDir)) {
1180
+ // Replace the empty stub from ensureSubdirs with the real copy.
1181
+ try { cpSync(sourceAbs, inDir, { recursive: true, force: true }); }
1182
+ catch (err: any) {
1183
+ console.error('Failed to copy source into input/: ' + err.message);
1184
+ process.exit(1);
1185
+ }
1186
+ // Strip noise.
1187
+ for (const noise of ['.gitnexus', 'node_modules', '.DS_Store']) {
1188
+ const p = resolve(inDir, noise);
1189
+ try { if (existsSync(p)) require('fs').rmSync(p, { recursive: true, force: true }); } catch {}
1190
+ }
1191
+ }
1192
+ } else {
1193
+ // Single-file source \u2014 copy it into input/ as-is.
1194
+ mkdirSync(inDir, { recursive: true });
1195
+ cpSync(sourceAbs, resolve(inDir, basename(sourceAbs)));
1196
+ }
1197
+
1198
+ console.log(' source: ' + sourceAbs);
1199
+ console.log(' output: ' + outputDir);
1200
+ console.log(' provider: ' + providerId);
1201
+ if (options.facts) console.log(' facts: ' + options.facts);
1202
+ if (options.autoFacts) console.log(' facts: auto (runPrepass)');
1203
+ if (options.verify) console.log(' verify: enabled');
1204
+ if (options.realize) console.log(' realize: enabled');
1205
+
1206
+ try {
1207
+ const result = await runAnalyse({
1208
+ sourceDir: inDir,
1209
+ outputDir,
1210
+ factsPath: options.facts ? resolve(userCwd, options.facts) : undefined,
1211
+ autoFacts: !!options.autoFacts,
1212
+ verify: !!options.verify,
1213
+ realize: !!options.realize,
1214
+ prompt: 'analyse-v9',
1215
+ providerId,
1216
+ modelId,
1217
+ caseName: basename(sourceAbs),
1218
+ });
1219
+ console.log('');
1220
+ console.log('\u2705 Analyse complete');
1221
+ console.log(' Final spec: ' + result.finalSpecPath);
1222
+ console.log(' Validate: ' + (result.validateFinal.ok ? '\u2713 pass' : '\u2717 ' + result.validateFinal.errors.slice(0, 100)));
1223
+ if (result.realize) {
1224
+ console.log(' Realize: ' + (result.realize.ok ? '\u2713 project/ materialized' : '\u2717 ' + result.realize.error));
1225
+ }
1226
+ console.log(' README: ' + outputDir + '/README.md');
1227
+ } catch (err: any) {
1228
+ console.error('Analyse failed: ' + (err?.message || err));
1229
+ process.exit(1);
1230
+ }`
1231
+ },
1232
+ "ai.create": {
1233
+ imports: `import { resolve, basename } from 'path';
1234
+ import { existsSync, readFileSync } from 'fs';`,
1235
+ handler: `const userCwd = process.env.SPECVERSE_USER_CWD || process.cwd();
1236
+ // Resolve requirements: positional arg, or read from --file.
1237
+ let reqText = requirements;
1238
+ if (options.file) {
1239
+ const fp = resolve(userCwd, options.file);
1240
+ if (!existsSync(fp)) {
1241
+ console.error('Requirements file not found: ' + fp);
1242
+ process.exit(1);
1243
+ }
1244
+ reqText = readFileSync(fp, 'utf8');
1245
+ }
1246
+ if (!reqText || !reqText.trim()) {
1247
+ console.error('No requirements provided. Pass them as a positional argument or via --file.');
1248
+ process.exit(1);
1249
+ }
1250
+
1251
+ const { runCreate, buildRunFolder, caseRunPath, ensureSubdirs, resolveProviderId } = await import('@specverse/engines/ai');
1252
+ const providerId = resolveProviderId();
1253
+ const modelId = process.env.SPECVERSE_AI_MODEL || 'default';
1254
+ const runFolder = buildRunFolder({
1255
+ prompt: 'create-v9',
1256
+ providerId,
1257
+ modelId,
1258
+ label: options.label,
1259
+ });
1260
+ // Default output: ./runs/create/<short-slug>/<date>_<label>/
1261
+ const slug = (options.name || 'spec').toLowerCase().replace(/[^a-z0-9-]+/g, '-').slice(0, 40) || 'spec';
1262
+ const outputDir = options.output
1263
+ ? resolve(userCwd, options.output)
1264
+ : caseRunPath(userCwd, 'create', slug, runFolder);
1265
+ ensureSubdirs(outputDir);
1266
+
1267
+ console.log(' output: ' + outputDir);
1268
+ console.log(' provider: ' + providerId);
1269
+ if (options.scale) console.log(' scale: ' + options.scale);
1270
+ if (options.preferredTech) console.log(' tech: ' + options.preferredTech);
1271
+ if (options.verify) console.log(' verify: enabled');
1272
+ if (options.realize) console.log(' realize: enabled');
1273
+
1274
+ try {
1275
+ const result = await runCreate({
1276
+ requirements: reqText,
1277
+ scale: options.scale,
1278
+ preferredTech: options.preferredTech,
1279
+ outputDir,
1280
+ verify: !!options.verify,
1281
+ realize: !!options.realize,
1282
+ prompt: 'create-v9',
1283
+ providerId,
1284
+ modelId,
1285
+ caseName: slug,
1286
+ });
1287
+ console.log('');
1288
+ console.log('\u2705 Create complete');
1289
+ console.log(' Final spec: ' + result.finalSpecPath);
1290
+ console.log(' Validate: ' + (result.validateFinal.ok ? '\u2713 pass' : '\u2717 ' + result.validateFinal.errors.slice(0, 100)));
1291
+ if (result.realize) {
1292
+ console.log(' Realize: ' + (result.realize.ok ? '\u2713 project/ materialized' : '\u2717 ' + result.realize.error));
1293
+ }
1294
+ console.log(' README: ' + outputDir + '/README.md');
1295
+ } catch (err: any) {
1296
+ console.error('Create failed: ' + (err?.message || err));
1297
+ process.exit(1);
1298
+ }`
1299
+ },
1148
1300
  // === session subcommands ===
1149
1301
  "session.create": {
1150
1302
  imports: `import { EngineRegistry } from '@specverse/entities';`,
@@ -1200,6 +1200,158 @@ import type { ParserEngine } from '@specverse/types';`,
1200
1200
  process.exit(1);
1201
1201
  }`
1202
1202
  },
1203
+ 'ai.analyse': {
1204
+ imports: `import { resolve, basename } from 'path';
1205
+ import { existsSync, mkdirSync, cpSync, statSync, readdirSync } from 'fs';`,
1206
+ handler: `// Resolve the absolute source dir.
1207
+ const userCwd = process.env.SPECVERSE_USER_CWD || process.cwd();
1208
+ const sourceAbs = resolve(userCwd, source);
1209
+ if (!existsSync(sourceAbs)) {
1210
+ console.error('Source dir not found: ' + sourceAbs);
1211
+ process.exit(1);
1212
+ }
1213
+
1214
+ // Default output: ./runs/analyse/<basename>/<date>_<label>/
1215
+ const { runAnalyse, buildRunFolder, caseRunPath, ensureSubdirs, inputDir, resolveProviderId } = await import('@specverse/engines/ai');
1216
+ const providerId = resolveProviderId();
1217
+ const modelId = process.env.SPECVERSE_AI_MODEL || 'default';
1218
+ const runFolder = buildRunFolder({
1219
+ prompt: 'analyse-v9',
1220
+ providerId,
1221
+ modelId,
1222
+ label: options.label,
1223
+ });
1224
+ const outputDir = options.output
1225
+ ? resolve(userCwd, options.output)
1226
+ : caseRunPath(userCwd, 'analyse', basename(sourceAbs), runFolder);
1227
+ ensureSubdirs(outputDir);
1228
+
1229
+ // Copy source into outputDir/input/ (excluding noisy indices) so the
1230
+ // run dir is self-contained.
1231
+ const inDir = inputDir(outputDir);
1232
+ const stat = statSync(sourceAbs);
1233
+ if (stat.isDirectory()) {
1234
+ if (existsSync(inDir)) {
1235
+ // Replace the empty stub from ensureSubdirs with the real copy.
1236
+ try { cpSync(sourceAbs, inDir, { recursive: true, force: true }); }
1237
+ catch (err: any) {
1238
+ console.error('Failed to copy source into input/: ' + err.message);
1239
+ process.exit(1);
1240
+ }
1241
+ // Strip noise.
1242
+ for (const noise of ['.gitnexus', 'node_modules', '.DS_Store']) {
1243
+ const p = resolve(inDir, noise);
1244
+ try { if (existsSync(p)) require('fs').rmSync(p, { recursive: true, force: true }); } catch {}
1245
+ }
1246
+ }
1247
+ } else {
1248
+ // Single-file source — copy it into input/ as-is.
1249
+ mkdirSync(inDir, { recursive: true });
1250
+ cpSync(sourceAbs, resolve(inDir, basename(sourceAbs)));
1251
+ }
1252
+
1253
+ console.log(' source: ' + sourceAbs);
1254
+ console.log(' output: ' + outputDir);
1255
+ console.log(' provider: ' + providerId);
1256
+ if (options.facts) console.log(' facts: ' + options.facts);
1257
+ if (options.autoFacts) console.log(' facts: auto (runPrepass)');
1258
+ if (options.verify) console.log(' verify: enabled');
1259
+ if (options.realize) console.log(' realize: enabled');
1260
+
1261
+ try {
1262
+ const result = await runAnalyse({
1263
+ sourceDir: inDir,
1264
+ outputDir,
1265
+ factsPath: options.facts ? resolve(userCwd, options.facts) : undefined,
1266
+ autoFacts: !!options.autoFacts,
1267
+ verify: !!options.verify,
1268
+ realize: !!options.realize,
1269
+ prompt: 'analyse-v9',
1270
+ providerId,
1271
+ modelId,
1272
+ caseName: basename(sourceAbs),
1273
+ });
1274
+ console.log('');
1275
+ console.log('✅ Analyse complete');
1276
+ console.log(' Final spec: ' + result.finalSpecPath);
1277
+ console.log(' Validate: ' + (result.validateFinal.ok ? '✓ pass' : '✗ ' + result.validateFinal.errors.slice(0, 100)));
1278
+ if (result.realize) {
1279
+ console.log(' Realize: ' + (result.realize.ok ? '✓ project/ materialized' : '✗ ' + result.realize.error));
1280
+ }
1281
+ console.log(' README: ' + outputDir + '/README.md');
1282
+ } catch (err: any) {
1283
+ console.error('Analyse failed: ' + (err?.message || err));
1284
+ process.exit(1);
1285
+ }`
1286
+ },
1287
+ 'ai.create': {
1288
+ imports: `import { resolve, basename } from 'path';
1289
+ import { existsSync, readFileSync } from 'fs';`,
1290
+ handler: `const userCwd = process.env.SPECVERSE_USER_CWD || process.cwd();
1291
+ // Resolve requirements: positional arg, or read from --file.
1292
+ let reqText = requirements;
1293
+ if (options.file) {
1294
+ const fp = resolve(userCwd, options.file);
1295
+ if (!existsSync(fp)) {
1296
+ console.error('Requirements file not found: ' + fp);
1297
+ process.exit(1);
1298
+ }
1299
+ reqText = readFileSync(fp, 'utf8');
1300
+ }
1301
+ if (!reqText || !reqText.trim()) {
1302
+ console.error('No requirements provided. Pass them as a positional argument or via --file.');
1303
+ process.exit(1);
1304
+ }
1305
+
1306
+ const { runCreate, buildRunFolder, caseRunPath, ensureSubdirs, resolveProviderId } = await import('@specverse/engines/ai');
1307
+ const providerId = resolveProviderId();
1308
+ const modelId = process.env.SPECVERSE_AI_MODEL || 'default';
1309
+ const runFolder = buildRunFolder({
1310
+ prompt: 'create-v9',
1311
+ providerId,
1312
+ modelId,
1313
+ label: options.label,
1314
+ });
1315
+ // Default output: ./runs/create/<short-slug>/<date>_<label>/
1316
+ const slug = (options.name || 'spec').toLowerCase().replace(/[^a-z0-9-]+/g, '-').slice(0, 40) || 'spec';
1317
+ const outputDir = options.output
1318
+ ? resolve(userCwd, options.output)
1319
+ : caseRunPath(userCwd, 'create', slug, runFolder);
1320
+ ensureSubdirs(outputDir);
1321
+
1322
+ console.log(' output: ' + outputDir);
1323
+ console.log(' provider: ' + providerId);
1324
+ if (options.scale) console.log(' scale: ' + options.scale);
1325
+ if (options.preferredTech) console.log(' tech: ' + options.preferredTech);
1326
+ if (options.verify) console.log(' verify: enabled');
1327
+ if (options.realize) console.log(' realize: enabled');
1328
+
1329
+ try {
1330
+ const result = await runCreate({
1331
+ requirements: reqText,
1332
+ scale: options.scale,
1333
+ preferredTech: options.preferredTech,
1334
+ outputDir,
1335
+ verify: !!options.verify,
1336
+ realize: !!options.realize,
1337
+ prompt: 'create-v9',
1338
+ providerId,
1339
+ modelId,
1340
+ caseName: slug,
1341
+ });
1342
+ console.log('');
1343
+ console.log('✅ Create complete');
1344
+ console.log(' Final spec: ' + result.finalSpecPath);
1345
+ console.log(' Validate: ' + (result.validateFinal.ok ? '✓ pass' : '✗ ' + result.validateFinal.errors.slice(0, 100)));
1346
+ if (result.realize) {
1347
+ console.log(' Realize: ' + (result.realize.ok ? '✓ project/ materialized' : '✗ ' + result.realize.error));
1348
+ }
1349
+ console.log(' README: ' + outputDir + '/README.md');
1350
+ } catch (err: any) {
1351
+ console.error('Create failed: ' + (err?.message || err));
1352
+ process.exit(1);
1353
+ }`
1354
+ },
1203
1355
  // === session subcommands ===
1204
1356
  'session.create': {
1205
1357
  imports: `import { EngineRegistry } from '@specverse/entities';`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specverse/engines",
3
- "version": "6.0.13",
3
+ "version": "6.0.14",
4
4
  "description": "SpecVerse toolchain — parser, inference, realize, generators, AI, registry, bundles",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",