@traits-dev/cli 0.5.0 → 0.6.0

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/README.md CHANGED
@@ -15,7 +15,7 @@ traits init --template resolve profiles/resolve.yaml
15
15
  traits validate profiles/resolve.yaml
16
16
  traits validate profiles/resolve.yaml --format sarif
17
17
  traits compile profiles/resolve.yaml --model gpt-4o
18
- traits migrate profiles/legacy-v1-4.yaml
18
+ traits migrate profiles/legacy-v1-5.yaml --to v1.6 --normalize-extends
19
19
  traits eval profiles/resolve.yaml --tier 1
20
20
  ```
21
21
 
package/dist/traits.js CHANGED
@@ -267,7 +267,7 @@ function printEvalUsage(out = process.stderr) {
267
267
  "Options:",
268
268
  " --model <model> Model target (required)",
269
269
  " --tier <1|2|3> Highest tier to run (default: highest available)",
270
- " --suite <name> Built-in baseline suite: support|healthcare|developer",
270
+ " --suite <name> Built-in baseline suite: support|healthcare|developer|educator|advisor",
271
271
  " --provider <name> Judge provider for Tier 3: auto|openai|anthropic",
272
272
  " --embedding-model <name> Embedding model for Tier 2 (OpenAI)",
273
273
  " --judge-model <name> Judge model for Tier 3 provider",
@@ -402,10 +402,12 @@ function parseEvalArgs(args) {
402
402
  if (!["auto", "openai", "anthropic"].includes(result.provider)) {
403
403
  return { error: 'Invalid "--provider" value. Expected auto, openai, or anthropic.' };
404
404
  }
405
- if (result.suite != null && !["support", "healthcare", "developer"].includes(
405
+ if (result.suite != null && !["support", "healthcare", "developer", "educator", "advisor"].includes(
406
406
  result.suite
407
407
  )) {
408
- return { error: 'Invalid "--suite" value. Expected support, healthcare, or developer.' };
408
+ return {
409
+ error: 'Invalid "--suite" value. Expected support, healthcare, developer, educator, or advisor.'
410
+ };
409
411
  }
410
412
  if (result.suite != null && result.samplesPath != null) {
411
413
  return { error: 'Use either "--suite" or "--samples/--scenarios", not both.' };
@@ -443,7 +445,7 @@ function loadSamples(options, cwd) {
443
445
  const suite = loadBuiltInEvalSuite(options.suite);
444
446
  if (!suite) {
445
447
  throw new Error(
446
- `Unknown suite "${options.suite}". Expected support, healthcare, or developer.`
448
+ `Unknown suite "${options.suite}". Expected support, healthcare, developer, educator, or advisor.`
447
449
  );
448
450
  }
449
451
  return suite.scenarios.map((scenario) => ({
@@ -1451,6 +1453,11 @@ import fs4 from "fs";
1451
1453
  import path5 from "path";
1452
1454
  import { loadProfileFile, validateResolvedProfile as validateResolvedProfile2 } from "@traits-dev/core";
1453
1455
  import { renderImportedProfileYAML, toValidationResultObject as toValidationResultObject4 } from "@traits-dev/core/internal";
1456
+ var SCHEMA_ORDER = {
1457
+ "v1.4": 0,
1458
+ "v1.5": 1,
1459
+ "v1.6": 2
1460
+ };
1454
1461
  function printMigrateUsage(out = process.stderr) {
1455
1462
  out.write(
1456
1463
  [
@@ -1458,10 +1465,11 @@ function printMigrateUsage(out = process.stderr) {
1458
1465
  " traits migrate <profile-path> [options]",
1459
1466
  "",
1460
1467
  "Options:",
1461
- " --to <version> Target schema version (default: v1.5)",
1462
- " --output <path> Output file path (default: <name>.v1.5.yaml)",
1468
+ " --to <version> Target schema version (default: v1.6; supported: v1.5, v1.6)",
1469
+ " --output <path> Output file path (default: <name>.<target>.yaml)",
1463
1470
  " --in-place Overwrite the source file (requires --force if file exists)",
1464
1471
  " --force Overwrite existing destination file",
1472
+ " --normalize-extends Convert single-string extends to array form (v1.6 target only)",
1465
1473
  " --json Output structured JSON summary",
1466
1474
  " --verbose Include additional command metadata",
1467
1475
  " --no-color Disable colorized output",
@@ -1472,10 +1480,11 @@ function printMigrateUsage(out = process.stderr) {
1472
1480
  function parseMigrateArgs(args) {
1473
1481
  const result = {
1474
1482
  profilePath: null,
1475
- to: "v1.5",
1483
+ to: "v1.6",
1476
1484
  outputPath: null,
1477
1485
  inPlace: false,
1478
1486
  force: false,
1487
+ normalizeExtends: false,
1479
1488
  json: false,
1480
1489
  verbose: false,
1481
1490
  noColor: false
@@ -1491,6 +1500,10 @@ function parseMigrateArgs(args) {
1491
1500
  result.force = true;
1492
1501
  continue;
1493
1502
  }
1503
+ if (arg === "--normalize-extends") {
1504
+ result.normalizeExtends = true;
1505
+ continue;
1506
+ }
1494
1507
  if (arg === "--json") {
1495
1508
  result.json = true;
1496
1509
  continue;
@@ -1507,12 +1520,12 @@ function parseMigrateArgs(args) {
1507
1520
  const value = args[index + 1];
1508
1521
  if (!value) return { error: `Missing value for "${arg}"` };
1509
1522
  if (arg === "--to") {
1510
- if (value !== "v1.5") {
1523
+ if (value !== "v1.5" && value !== "v1.6") {
1511
1524
  return {
1512
- error: `Unsupported "--to" value "${value}". Currently supported: v1.5`
1525
+ error: `Unsupported "--to" value "${value}". Currently supported: v1.5, v1.6`
1513
1526
  };
1514
1527
  }
1515
- result.to = "v1.5";
1528
+ result.to = value;
1516
1529
  } else {
1517
1530
  result.outputPath = value;
1518
1531
  }
@@ -1531,6 +1544,9 @@ function parseMigrateArgs(args) {
1531
1544
  if (result.inPlace && result.outputPath) {
1532
1545
  return { error: 'Use either "--in-place" or "--output", not both.' };
1533
1546
  }
1547
+ if (result.normalizeExtends && result.to !== "v1.6") {
1548
+ return { error: '"--normalize-extends" requires "--to v1.6".' };
1549
+ }
1534
1550
  return { value: result };
1535
1551
  }
1536
1552
  function resolveDefaultOutputPath(sourcePath, toVersion) {
@@ -1563,6 +1579,22 @@ function migrateV14ToV15(profile) {
1563
1579
  }
1564
1580
  return { migrated, capabilitiesAdded: false };
1565
1581
  }
1582
+ function migrateV15ToV16(profile, options) {
1583
+ const migrated = JSON.parse(JSON.stringify(profile));
1584
+ migrated.schema = "v1.6";
1585
+ if (options.normalizeExtends && typeof migrated.extends === "string") {
1586
+ const normalized = migrated.extends.trim();
1587
+ if (normalized.length > 0) {
1588
+ migrated.extends = [normalized];
1589
+ return { migrated, extendsNormalized: true };
1590
+ }
1591
+ }
1592
+ return { migrated, extendsNormalized: false };
1593
+ }
1594
+ function asSupportedSourceSchema(value) {
1595
+ if (value === "v1.4" || value === "v1.5") return value;
1596
+ return null;
1597
+ }
1566
1598
  function runMigrate(args, io = process) {
1567
1599
  const parsed = parseMigrateArgs(args);
1568
1600
  if ("error" in parsed) {
@@ -1602,15 +1634,58 @@ function runMigrate(args, io = process) {
1602
1634
  );
1603
1635
  return 1;
1604
1636
  }
1605
- if (loaded.schema !== "v1.4") {
1637
+ if (loaded.schema === "v1.6") {
1638
+ io.stderr.write(
1639
+ 'Error: Source profile is already at "v1.6". Nothing to migrate.\n'
1640
+ );
1641
+ return 1;
1642
+ }
1643
+ const sourceSchema = asSupportedSourceSchema(loaded.schema);
1644
+ if (!sourceSchema) {
1645
+ io.stderr.write(
1646
+ `Error: Migration source schema must be "v1.4" or "v1.5". Found "${loaded.schema ?? "unknown"}".
1647
+ `
1648
+ );
1649
+ return 1;
1650
+ }
1651
+ if (SCHEMA_ORDER[options.to] < SCHEMA_ORDER[sourceSchema]) {
1606
1652
  io.stderr.write(
1607
- `Error: Migration source schema must be "v1.4". Found "${loaded.schema ?? "unknown"}".
1653
+ `Error: Downgrade is not supported (source "${sourceSchema}" -> target "${options.to}").
1608
1654
  `
1609
1655
  );
1610
1656
  return 1;
1611
1657
  }
1612
- const migration = migrateV14ToV15(loaded);
1613
- const validation = validateResolvedProfile2(migration.migrated, {
1658
+ if (SCHEMA_ORDER[options.to] === SCHEMA_ORDER[sourceSchema]) {
1659
+ io.stderr.write(`Error: Source profile already uses target schema "${options.to}".
1660
+ `);
1661
+ return 1;
1662
+ }
1663
+ let migrated = loaded;
1664
+ let capabilitiesAdded = false;
1665
+ let extendsNormalized = false;
1666
+ let currentSchema = sourceSchema;
1667
+ if (currentSchema === "v1.4") {
1668
+ const step = migrateV14ToV15(migrated);
1669
+ migrated = step.migrated;
1670
+ capabilitiesAdded = step.capabilitiesAdded;
1671
+ currentSchema = "v1.5";
1672
+ }
1673
+ if (options.to === "v1.6" && currentSchema === "v1.5") {
1674
+ const step = migrateV15ToV16(migrated, {
1675
+ normalizeExtends: options.normalizeExtends
1676
+ });
1677
+ migrated = step.migrated;
1678
+ extendsNormalized = step.extendsNormalized;
1679
+ currentSchema = "v1.6";
1680
+ }
1681
+ if (currentSchema !== options.to) {
1682
+ io.stderr.write(
1683
+ `Error: Failed to migrate profile to target schema "${options.to}". Final schema: "${currentSchema}".
1684
+ `
1685
+ );
1686
+ return 2;
1687
+ }
1688
+ const validation = validateResolvedProfile2(migrated, {
1614
1689
  strict: false
1615
1690
  });
1616
1691
  if (validation.errors.length > 0) {
@@ -1620,7 +1695,7 @@ function runMigrate(args, io = process) {
1620
1695
  );
1621
1696
  return 2;
1622
1697
  }
1623
- const yaml = renderImportedProfileYAML(migration.migrated);
1698
+ const yaml = renderImportedProfileYAML(migrated);
1624
1699
  writeFileAtomic2(destinationPath, yaml);
1625
1700
  if (options.json) {
1626
1701
  io.stdout.write(
@@ -1629,9 +1704,10 @@ function runMigrate(args, io = process) {
1629
1704
  migrated: true,
1630
1705
  sourcePath,
1631
1706
  outputPath: destinationPath,
1632
- fromSchema: "v1.4",
1633
- toSchema: "v1.5",
1634
- capabilitiesAdded: migration.capabilitiesAdded,
1707
+ fromSchema: sourceSchema,
1708
+ toSchema: options.to,
1709
+ capabilitiesAdded,
1710
+ extendsNormalized,
1635
1711
  validation: toValidationResultObject4(validation)
1636
1712
  },
1637
1713
  null,
@@ -1646,13 +1722,15 @@ function runMigrate(args, io = process) {
1646
1722
  `);
1647
1723
  io.stdout.write(`Output: ${destinationPath}
1648
1724
  `);
1649
- io.stdout.write(`Capabilities added: ${migration.capabilitiesAdded ? "yes" : "no"}
1725
+ io.stdout.write(`Capabilities added: ${capabilitiesAdded ? "yes" : "no"}
1726
+ `);
1727
+ io.stdout.write(`Extends normalized: ${extendsNormalized ? "yes" : "no"}
1650
1728
  `);
1651
1729
  io.stdout.write(`Validation warnings: ${validation.warnings.length}
1652
1730
 
1653
1731
  `);
1654
1732
  }
1655
- io.stdout.write(`Migrated profile schema v1.4 -> v1.5
1733
+ io.stdout.write(`Migrated profile schema ${sourceSchema} -> ${options.to}
1656
1734
  `);
1657
1735
  io.stdout.write(`Wrote: ${destinationPath}
1658
1736
  `);
@@ -1871,7 +1949,7 @@ function printRootUsage(out = process.stdout) {
1871
1949
  " compile <profile-path> Compile a profile for a target model",
1872
1950
  " eval <profile-path> Evaluate profile responses (Tier 1 scaffold)",
1873
1951
  " import [prompt-path] Import a profile from an existing system prompt",
1874
- " migrate <profile-path> Migrate profile schema (v1.4 -> v1.5)",
1952
+ " migrate <profile-path> Migrate profile schema (up to v1.6)",
1875
1953
  " validate <profile-path> Validate a voice profile",
1876
1954
  "",
1877
1955
  "Global flags:",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@traits-dev/cli",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "traits.dev command-line interface for voice profile init, validate, compile, eval, and import workflows.",
5
5
  "keywords": [
6
6
  "traits-dev",
@@ -41,7 +41,7 @@
41
41
  "provenance": true
42
42
  },
43
43
  "dependencies": {
44
- "@traits-dev/core": "^0.5.0"
44
+ "@traits-dev/core": "^0.6.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/node": "^25.2.3",