@traits-dev/cli 0.3.0 → 0.5.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Justin Hambleton
3
+ Copyright (c) 2026 FRNTR, LLC
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @traits-dev/cli
2
2
 
3
- CLI for traits.dev voice profile workflows: init, validate, compile, eval, and import.
3
+ CLI for traits.dev voice profile workflows: init, validate, compile, eval, import, and migrate.
4
4
 
5
5
  ## Install
6
6
 
@@ -13,7 +13,9 @@ pnpm add -D @traits-dev/cli
13
13
  ```bash
14
14
  traits init --template resolve profiles/resolve.yaml
15
15
  traits validate profiles/resolve.yaml
16
+ traits validate profiles/resolve.yaml --format sarif
16
17
  traits compile profiles/resolve.yaml --model gpt-4o
18
+ traits migrate profiles/legacy-v1-4.yaml
17
19
  traits eval profiles/resolve.yaml --tier 1
18
20
  ```
19
21
 
package/dist/traits.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/bin/traits.ts
4
- import fs4 from "fs";
5
- import path6 from "path";
4
+ import fs5 from "fs";
5
+ import path7 from "path";
6
6
  import { fileURLToPath } from "url";
7
7
 
8
8
  // src/commands/compile.ts
@@ -22,6 +22,8 @@ function printCompileUsage(out = process.stderr) {
22
22
  " --model <model> Model target (required)",
23
23
  " --json Output structured JSON",
24
24
  " --strict Treat warnings as compile-blocking",
25
+ " --budget Print estimated token count (chars/4)",
26
+ " --budget-limit <tokens> Warn to stderr if estimate exceeds limit",
25
27
  " --explain Include compilation trace output",
26
28
  " --context key=value Activate context adaptation (repeatable)",
27
29
  " --knowledge-base-dir Directory containing compiler pattern files",
@@ -52,6 +54,8 @@ function parseCompileArgs(args) {
52
54
  model: null,
53
55
  strict: false,
54
56
  json: false,
57
+ budget: false,
58
+ budgetLimit: null,
55
59
  explain: false,
56
60
  verbose: false,
57
61
  noColor: false,
@@ -70,6 +74,10 @@ function parseCompileArgs(args) {
70
74
  result.json = true;
71
75
  continue;
72
76
  }
77
+ if (arg === "--budget") {
78
+ result.budget = true;
79
+ continue;
80
+ }
73
81
  if (arg === "--explain") {
74
82
  result.explain = true;
75
83
  continue;
@@ -82,7 +90,7 @@ function parseCompileArgs(args) {
82
90
  result.noColor = true;
83
91
  continue;
84
92
  }
85
- if (arg === "--model" || arg === "--bundled-profiles-dir" || arg === "--context" || arg === "--knowledge-base-dir") {
93
+ if (arg === "--model" || arg === "--bundled-profiles-dir" || arg === "--context" || arg === "--knowledge-base-dir" || arg === "--budget-limit") {
86
94
  const value = args[index + 1];
87
95
  if (!value) return { error: `Missing value for "${arg}"` };
88
96
  if (arg === "--model") {
@@ -91,6 +99,12 @@ function parseCompileArgs(args) {
91
99
  result.bundledProfilesDir = value;
92
100
  } else if (arg === "--knowledge-base-dir") {
93
101
  result.knowledgeBaseDir = value;
102
+ } else if (arg === "--budget-limit") {
103
+ const parsedBudgetLimit = Number(value);
104
+ if (!Number.isFinite(parsedBudgetLimit) || parsedBudgetLimit <= 0) {
105
+ return { error: `Invalid value for "--budget-limit": "${value}"` };
106
+ }
107
+ result.budgetLimit = Math.round(parsedBudgetLimit);
94
108
  } else {
95
109
  const parsedContext = parseContextArg(value);
96
110
  if ("error" in parsedContext) return { error: parsedContext.error };
@@ -111,8 +125,14 @@ function parseCompileArgs(args) {
111
125
  if (!result.model) {
112
126
  return { error: 'Missing required option "--model"' };
113
127
  }
128
+ if (result.budgetLimit != null) {
129
+ result.budget = true;
130
+ }
114
131
  return { value: result };
115
132
  }
133
+ function estimateBudgetTokens(text) {
134
+ return Math.ceil(String(text ?? "").length / 4);
135
+ }
116
136
  function runCompile(args, io = process) {
117
137
  const parsed = parseCompileArgs(args);
118
138
  if ("error" in parsed) {
@@ -156,10 +176,32 @@ function runCompile(args, io = process) {
156
176
  if (options.json) {
157
177
  io.stdout.write(`${JSON.stringify(compiled, null, 2)}
158
178
  `);
179
+ if (options.budget) {
180
+ const budgetEstimate = estimateBudgetTokens(compiled.text);
181
+ io.stderr.write(`Estimated token count: ${budgetEstimate}
182
+ `);
183
+ if (options.budgetLimit != null && budgetEstimate > options.budgetLimit) {
184
+ io.stderr.write(
185
+ `Warning: Estimated token count ${budgetEstimate} exceeds budget limit ${options.budgetLimit}
186
+ `
187
+ );
188
+ }
189
+ }
159
190
  return 0;
160
191
  }
161
192
  io.stdout.write(`${compiled.text}
162
193
  `);
194
+ if (options.budget) {
195
+ const budgetEstimate = estimateBudgetTokens(compiled.text);
196
+ io.stderr.write(`Estimated token count: ${budgetEstimate}
197
+ `);
198
+ if (options.budgetLimit != null && budgetEstimate > options.budgetLimit) {
199
+ io.stderr.write(
200
+ `Warning: Estimated token count ${budgetEstimate} exceeds budget limit ${options.budgetLimit}
201
+ `
202
+ );
203
+ }
204
+ }
163
205
  if (options.explain && compiled.trace) {
164
206
  io.stdout.write(`
165
207
  [TRACE]
@@ -1404,21 +1446,238 @@ function importHelp(out = process.stdout) {
1404
1446
  printImportUsage(out);
1405
1447
  }
1406
1448
 
1407
- // src/commands/validate.ts
1449
+ // src/commands/migrate.ts
1450
+ import fs4 from "fs";
1408
1451
  import path5 from "path";
1452
+ import { loadProfileFile, validateResolvedProfile as validateResolvedProfile2 } from "@traits-dev/core";
1453
+ import { renderImportedProfileYAML, toValidationResultObject as toValidationResultObject4 } from "@traits-dev/core/internal";
1454
+ function printMigrateUsage(out = process.stderr) {
1455
+ out.write(
1456
+ [
1457
+ "Usage:",
1458
+ " traits migrate <profile-path> [options]",
1459
+ "",
1460
+ "Options:",
1461
+ " --to <version> Target schema version (default: v1.5)",
1462
+ " --output <path> Output file path (default: <name>.v1.5.yaml)",
1463
+ " --in-place Overwrite the source file (requires --force if file exists)",
1464
+ " --force Overwrite existing destination file",
1465
+ " --json Output structured JSON summary",
1466
+ " --verbose Include additional command metadata",
1467
+ " --no-color Disable colorized output",
1468
+ ""
1469
+ ].join("\n")
1470
+ );
1471
+ }
1472
+ function parseMigrateArgs(args) {
1473
+ const result = {
1474
+ profilePath: null,
1475
+ to: "v1.5",
1476
+ outputPath: null,
1477
+ inPlace: false,
1478
+ force: false,
1479
+ json: false,
1480
+ verbose: false,
1481
+ noColor: false
1482
+ };
1483
+ const positionals = [];
1484
+ for (let index = 0; index < args.length; index += 1) {
1485
+ const arg = args[index];
1486
+ if (arg === "--in-place") {
1487
+ result.inPlace = true;
1488
+ continue;
1489
+ }
1490
+ if (arg === "--force") {
1491
+ result.force = true;
1492
+ continue;
1493
+ }
1494
+ if (arg === "--json") {
1495
+ result.json = true;
1496
+ continue;
1497
+ }
1498
+ if (arg === "--verbose") {
1499
+ result.verbose = true;
1500
+ continue;
1501
+ }
1502
+ if (arg === "--no-color") {
1503
+ result.noColor = true;
1504
+ continue;
1505
+ }
1506
+ if (arg === "--to" || arg === "--output") {
1507
+ const value = args[index + 1];
1508
+ if (!value) return { error: `Missing value for "${arg}"` };
1509
+ if (arg === "--to") {
1510
+ if (value !== "v1.5") {
1511
+ return {
1512
+ error: `Unsupported "--to" value "${value}". Currently supported: v1.5`
1513
+ };
1514
+ }
1515
+ result.to = "v1.5";
1516
+ } else {
1517
+ result.outputPath = value;
1518
+ }
1519
+ index += 1;
1520
+ continue;
1521
+ }
1522
+ if (arg.startsWith("--")) {
1523
+ return { error: `Unknown option "${arg}"` };
1524
+ }
1525
+ positionals.push(arg);
1526
+ }
1527
+ if (positionals.length !== 1) {
1528
+ return { error: "Expected exactly one profile path argument" };
1529
+ }
1530
+ result.profilePath = positionals[0];
1531
+ if (result.inPlace && result.outputPath) {
1532
+ return { error: 'Use either "--in-place" or "--output", not both.' };
1533
+ }
1534
+ return { value: result };
1535
+ }
1536
+ function resolveDefaultOutputPath(sourcePath, toVersion) {
1537
+ const ext = path5.extname(sourcePath) || ".yaml";
1538
+ const base = sourcePath.slice(0, sourcePath.length - ext.length);
1539
+ return `${base}.${toVersion}${ext}`;
1540
+ }
1541
+ function writeFileAtomic2(filePath, contents) {
1542
+ fs4.mkdirSync(path5.dirname(filePath), { recursive: true });
1543
+ const tempFile = path5.join(
1544
+ path5.dirname(filePath),
1545
+ `.${path5.basename(filePath)}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`
1546
+ );
1547
+ fs4.writeFileSync(tempFile, contents, "utf8");
1548
+ fs4.renameSync(tempFile, filePath);
1549
+ }
1550
+ function migrateV14ToV15(profile) {
1551
+ const migrated = JSON.parse(JSON.stringify(profile));
1552
+ migrated.schema = "v1.5";
1553
+ if (!migrated.capabilities) {
1554
+ migrated.capabilities = {
1555
+ tools: [],
1556
+ constraints: [],
1557
+ handoff: {
1558
+ trigger: "Request requires unavailable operations.",
1559
+ action: "Offer handoff to a human operator."
1560
+ }
1561
+ };
1562
+ return { migrated, capabilitiesAdded: true };
1563
+ }
1564
+ return { migrated, capabilitiesAdded: false };
1565
+ }
1566
+ function runMigrate(args, io = process) {
1567
+ const parsed = parseMigrateArgs(args);
1568
+ if ("error" in parsed) {
1569
+ io.stderr.write(`Error: ${parsed.error}
1570
+
1571
+ `);
1572
+ printMigrateUsage(io.stderr);
1573
+ return 1;
1574
+ }
1575
+ const options = parsed.value;
1576
+ if (!options.profilePath) {
1577
+ io.stderr.write("Error: Missing profile path\n\n");
1578
+ printMigrateUsage(io.stderr);
1579
+ return 1;
1580
+ }
1581
+ const sourcePath = path5.resolve(io.cwd(), options.profilePath);
1582
+ const destinationPath = options.inPlace ? sourcePath : options.outputPath ? path5.resolve(io.cwd(), options.outputPath) : resolveDefaultOutputPath(sourcePath, options.to);
1583
+ if (!fs4.existsSync(sourcePath)) {
1584
+ io.stderr.write(`Error: Source profile does not exist: ${sourcePath}
1585
+ `);
1586
+ return 1;
1587
+ }
1588
+ if (fs4.existsSync(destinationPath) && !options.force) {
1589
+ io.stderr.write(
1590
+ `Error: Destination file already exists: ${destinationPath}. Use --force to overwrite.
1591
+ `
1592
+ );
1593
+ return 1;
1594
+ }
1595
+ let loaded;
1596
+ try {
1597
+ loaded = loadProfileFile(sourcePath);
1598
+ } catch (error) {
1599
+ io.stderr.write(
1600
+ `Error: Failed to read profile: ${error instanceof Error ? error.message : String(error)}
1601
+ `
1602
+ );
1603
+ return 1;
1604
+ }
1605
+ if (loaded.schema !== "v1.4") {
1606
+ io.stderr.write(
1607
+ `Error: Migration source schema must be "v1.4". Found "${loaded.schema ?? "unknown"}".
1608
+ `
1609
+ );
1610
+ return 1;
1611
+ }
1612
+ const migration = migrateV14ToV15(loaded);
1613
+ const validation = validateResolvedProfile2(migration.migrated, {
1614
+ strict: false
1615
+ });
1616
+ if (validation.errors.length > 0) {
1617
+ io.stderr.write(
1618
+ `Error: Migrated profile is invalid and was not written (${validation.errors.length} error(s)).
1619
+ `
1620
+ );
1621
+ return 2;
1622
+ }
1623
+ const yaml = renderImportedProfileYAML(migration.migrated);
1624
+ writeFileAtomic2(destinationPath, yaml);
1625
+ if (options.json) {
1626
+ io.stdout.write(
1627
+ `${JSON.stringify(
1628
+ {
1629
+ migrated: true,
1630
+ sourcePath,
1631
+ outputPath: destinationPath,
1632
+ fromSchema: "v1.4",
1633
+ toSchema: "v1.5",
1634
+ capabilitiesAdded: migration.capabilitiesAdded,
1635
+ validation: toValidationResultObject4(validation)
1636
+ },
1637
+ null,
1638
+ 2
1639
+ )}
1640
+ `
1641
+ );
1642
+ return 0;
1643
+ }
1644
+ if (options.verbose) {
1645
+ io.stdout.write(`Source: ${sourcePath}
1646
+ `);
1647
+ io.stdout.write(`Output: ${destinationPath}
1648
+ `);
1649
+ io.stdout.write(`Capabilities added: ${migration.capabilitiesAdded ? "yes" : "no"}
1650
+ `);
1651
+ io.stdout.write(`Validation warnings: ${validation.warnings.length}
1652
+
1653
+ `);
1654
+ }
1655
+ io.stdout.write(`Migrated profile schema v1.4 -> v1.5
1656
+ `);
1657
+ io.stdout.write(`Wrote: ${destinationPath}
1658
+ `);
1659
+ return 0;
1660
+ }
1661
+ function migrateHelp(out = process.stdout) {
1662
+ printMigrateUsage(out);
1663
+ }
1664
+
1665
+ // src/commands/validate.ts
1666
+ import path6 from "path";
1409
1667
  import { validateProfile as validateProfile2 } from "@traits-dev/core";
1410
1668
  import {
1411
1669
  formatValidationResult as formatValidationResult4,
1412
- toValidationResultObject as toValidationResultObject4
1670
+ toValidationResultObject as toValidationResultObject5
1413
1671
  } from "@traits-dev/core/internal";
1414
1672
  function printValidateUsage(out = process.stderr) {
1415
1673
  out.write(
1416
1674
  [
1417
1675
  "Usage:",
1418
- " traits validate <profile-path> [--json] [--strict] [--bundled-profiles-dir <dir>]",
1676
+ " traits validate <profile-path> [options]",
1419
1677
  "",
1420
1678
  "Options:",
1421
1679
  " --json Output structured JSON",
1680
+ " --format <text|json|sarif> Output format (default: text)",
1422
1681
  " --strict Promote warnings to errors",
1423
1682
  " --verbose Include additional command metadata",
1424
1683
  " --no-color Disable colorized output",
@@ -1432,6 +1691,7 @@ function parseValidateArgs(args) {
1432
1691
  profilePath: null,
1433
1692
  strict: false,
1434
1693
  json: false,
1694
+ format: "text",
1435
1695
  verbose: false,
1436
1696
  noColor: false,
1437
1697
  bundledProfilesDir: null
@@ -1445,6 +1705,7 @@ function parseValidateArgs(args) {
1445
1705
  }
1446
1706
  if (arg === "--json") {
1447
1707
  result.json = true;
1708
+ result.format = "json";
1448
1709
  continue;
1449
1710
  }
1450
1711
  if (arg === "--verbose") {
@@ -1464,6 +1725,20 @@ function parseValidateArgs(args) {
1464
1725
  index += 1;
1465
1726
  continue;
1466
1727
  }
1728
+ if (arg === "--format") {
1729
+ const nextValue = args[index + 1];
1730
+ if (!nextValue) {
1731
+ return { error: 'Missing value for "--format"' };
1732
+ }
1733
+ const normalized = String(nextValue).toLowerCase();
1734
+ if (normalized !== "text" && normalized !== "json" && normalized !== "sarif") {
1735
+ return { error: 'Invalid "--format" value. Expected text, json, or sarif.' };
1736
+ }
1737
+ result.format = normalized;
1738
+ result.json = normalized === "json";
1739
+ index += 1;
1740
+ continue;
1741
+ }
1467
1742
  if (arg.startsWith("--")) {
1468
1743
  return { error: `Unknown option "${arg}"` };
1469
1744
  }
@@ -1475,6 +1750,54 @@ function parseValidateArgs(args) {
1475
1750
  result.profilePath = positionals[0];
1476
1751
  return { value: result };
1477
1752
  }
1753
+ function toRelativePath(cwd, filePath) {
1754
+ const relative = path6.relative(cwd, filePath);
1755
+ if (relative && !relative.startsWith("..")) return relative;
1756
+ return filePath;
1757
+ }
1758
+ function buildSarifReport(validation, profilePath, cwd) {
1759
+ const diagnostics = [...validation.errors, ...validation.warnings];
1760
+ const uniqueRuleIds = [...new Set(diagnostics.map((diagnostic) => diagnostic.code))];
1761
+ const artifactUri = toRelativePath(cwd, profilePath);
1762
+ const rules = uniqueRuleIds.map((ruleId) => ({
1763
+ id: ruleId,
1764
+ shortDescription: {
1765
+ text: `traits.dev ${ruleId}`
1766
+ }
1767
+ }));
1768
+ const results = diagnostics.map((diagnostic) => ({
1769
+ ruleId: diagnostic.code,
1770
+ level: diagnostic.severity === "error" ? "error" : "warning",
1771
+ message: {
1772
+ text: diagnostic.message
1773
+ },
1774
+ locations: [
1775
+ {
1776
+ physicalLocation: {
1777
+ artifactLocation: {
1778
+ uri: artifactUri
1779
+ }
1780
+ }
1781
+ }
1782
+ ]
1783
+ }));
1784
+ return {
1785
+ version: "2.1.0",
1786
+ $schema: "https://json.schemastore.org/sarif-2.1.0.json",
1787
+ runs: [
1788
+ {
1789
+ tool: {
1790
+ driver: {
1791
+ name: "traits.dev",
1792
+ informationUri: "https://github.com/justinhambleton/traits",
1793
+ rules
1794
+ }
1795
+ },
1796
+ results
1797
+ }
1798
+ ]
1799
+ };
1800
+ }
1478
1801
  function runValidate(args, io = process) {
1479
1802
  const parsed = parseValidateArgs(args);
1480
1803
  if ("error" in parsed) {
@@ -1490,14 +1813,18 @@ function runValidate(args, io = process) {
1490
1813
  printValidateUsage(io.stderr);
1491
1814
  return 1;
1492
1815
  }
1493
- const bundledProfilesDir = options.bundledProfilesDir ? path5.resolve(io.cwd(), options.bundledProfilesDir) : path5.resolve(io.cwd(), "profiles");
1494
- const profilePath = path5.resolve(io.cwd(), options.profilePath);
1816
+ const bundledProfilesDir = options.bundledProfilesDir ? path6.resolve(io.cwd(), options.bundledProfilesDir) : path6.resolve(io.cwd(), "profiles");
1817
+ const profilePath = path6.resolve(io.cwd(), options.profilePath);
1495
1818
  const result = validateProfile2(profilePath, {
1496
1819
  strict: options.strict,
1497
1820
  bundledProfilesDir
1498
1821
  });
1499
- if (options.json) {
1500
- io.stdout.write(`${JSON.stringify(toValidationResultObject4(result), null, 2)}
1822
+ if (options.format === "json") {
1823
+ io.stdout.write(`${JSON.stringify(toValidationResultObject5(result), null, 2)}
1824
+ `);
1825
+ } else if (options.format === "sarif") {
1826
+ const sarif = buildSarifReport(result, profilePath, io.cwd());
1827
+ io.stdout.write(`${JSON.stringify(sarif, null, 2)}
1501
1828
  `);
1502
1829
  } else {
1503
1830
  if (options.verbose) {
@@ -1519,14 +1846,14 @@ function validateHelp(out = process.stdout) {
1519
1846
  }
1520
1847
 
1521
1848
  // src/bin/traits.ts
1522
- var CLI_DIR = path6.dirname(fileURLToPath(import.meta.url));
1849
+ var CLI_DIR = path7.dirname(fileURLToPath(import.meta.url));
1523
1850
  var PACKAGE_JSON_CANDIDATES = [
1524
- path6.resolve(CLI_DIR, "../package.json"),
1525
- path6.resolve(CLI_DIR, "../../package.json")
1851
+ path7.resolve(CLI_DIR, "../package.json"),
1852
+ path7.resolve(CLI_DIR, "../../package.json")
1526
1853
  ];
1527
1854
  function resolvePackageJsonPath() {
1528
1855
  for (const candidate of PACKAGE_JSON_CANDIDATES) {
1529
- if (fs4.existsSync(candidate)) return candidate;
1856
+ if (fs5.existsSync(candidate)) return candidate;
1530
1857
  }
1531
1858
  return PACKAGE_JSON_CANDIDATES[0];
1532
1859
  }
@@ -1544,6 +1871,7 @@ function printRootUsage(out = process.stdout) {
1544
1871
  " compile <profile-path> Compile a profile for a target model",
1545
1872
  " eval <profile-path> Evaluate profile responses (Tier 1 scaffold)",
1546
1873
  " import [prompt-path] Import a profile from an existing system prompt",
1874
+ " migrate <profile-path> Migrate profile schema (v1.4 -> v1.5)",
1547
1875
  " validate <profile-path> Validate a voice profile",
1548
1876
  "",
1549
1877
  "Global flags:",
@@ -1563,7 +1891,7 @@ function printRootUsage(out = process.stdout) {
1563
1891
  }
1564
1892
  function readCliVersion() {
1565
1893
  try {
1566
- const raw = fs4.readFileSync(PACKAGE_JSON_PATH, "utf8");
1894
+ const raw = fs5.readFileSync(PACKAGE_JSON_PATH, "utf8");
1567
1895
  const pkg = JSON.parse(raw);
1568
1896
  return String(pkg.version ?? "0.0.0");
1569
1897
  } catch {
@@ -1609,7 +1937,7 @@ function withGlobalFlags(command, commandArgs, flags) {
1609
1937
  if (flags.noColor && !args.includes("--no-color")) {
1610
1938
  args.push("--no-color");
1611
1939
  }
1612
- if ((command === "validate" || command === "compile" || command === "eval" || command === "import") && flags.json && !args.includes("--json")) {
1940
+ if ((command === "validate" || command === "compile" || command === "eval" || command === "import" || command === "migrate") && flags.json && !args.includes("--json")) {
1613
1941
  args.push("--json");
1614
1942
  }
1615
1943
  return args;
@@ -1675,6 +2003,13 @@ async function run(argv, io = process) {
1675
2003
  }
1676
2004
  return runImport(commandArgs, io);
1677
2005
  }
2006
+ if (command === "migrate") {
2007
+ if (commandArgs.includes("--help") || commandArgs.includes("-h")) {
2008
+ migrateHelp(io.stdout);
2009
+ return 0;
2010
+ }
2011
+ return runMigrate(commandArgs, io);
2012
+ }
1678
2013
  io.stderr.write(`Error: Unknown command "${command}"
1679
2014
 
1680
2015
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@traits-dev/cli",
3
- "version": "0.3.0",
3
+ "version": "0.5.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.3.0"
44
+ "@traits-dev/core": "^0.5.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/node": "^25.2.3",