@tekyzinc/gsd-t 2.9.0 → 2.10.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,118 @@
1
+ # Changelog
2
+
3
+ All notable changes to GSD-T are documented here. Updated with each release.
4
+
5
+ ## [2.10.1] - 2026-02-10
6
+
7
+ ### Added
8
+ - Automatic update check — CLI queries npm registry (cached 24h, background refresh) and shows a notice box with update commands when a newer version is available
9
+
10
+ ## [2.10.0] - 2026-02-10
11
+
12
+ ### Added
13
+ - `CHANGELOG.md` release notes document with full version history
14
+ - `changelog` CLI subcommand — opens changelog in the browser (`gsd-t changelog`)
15
+ - Clickable version links in CLI output (OSC 8 hyperlinks to changelog)
16
+ - `checkin` command now auto-updates CHANGELOG.md on every version bump
17
+ - `update-all` now creates CHANGELOG.md for registered projects that don't have one
18
+
19
+ ## [2.9.0] - 2026-02-10
20
+
21
+ ### Added
22
+ - `gsd-t-setup` command — generates or restructures project CLAUDE.md by scanning codebase, detecting tech stack/conventions, and removing global duplicates
23
+
24
+ ## [2.8.1] - 2026-02-10
25
+
26
+ ### Added
27
+ - Workflow Preferences section in global and project CLAUDE.md templates (Research Policy, Phase Flow defaults with per-project override support)
28
+
29
+ ## [2.8.0] - 2026-02-10
30
+
31
+ ### Added
32
+ - Backlog management system: 7 new commands (`backlog-add`, `backlog-list`, `backlog-move`, `backlog-edit`, `backlog-remove`, `backlog-promote`, `backlog-settings`)
33
+ - 2 new templates (`backlog.md`, `backlog-settings.md`)
34
+ - Backlog initialization in `gsd-t-init` with auto-category derivation
35
+ - Backlog summary in `gsd-t-status` report
36
+ - Backlog section in `gsd-t-help`
37
+
38
+ ### Changed
39
+ - Updated `gsd-t-init`, `gsd-t-status`, `gsd-t-help`, CLAUDE-global template, README with backlog integration
40
+
41
+ ## [2.7.0] - 2026-02-09
42
+
43
+ ### Added
44
+ - `update-all` CLI command — updates global install + all registered project CLAUDE.md files
45
+ - `register` CLI command — manually register a project in the GSD-T project registry
46
+ - Auto-registration on `gsd-t init`
47
+ - Project registry at `~/.claude/.gsd-t-projects`
48
+
49
+ ## [2.6.0] - 2026-02-09
50
+
51
+ ### Added
52
+ - Destructive Action Guard — mandatory safeguard requiring explicit user approval before destructive or structural changes (schema drops, architecture replacements, module removal)
53
+ - Guard enforced in global CLAUDE.md, project template, and all execution commands
54
+
55
+ ## [2.5.0] - 2026-02-09
56
+
57
+ ### Changed
58
+ - Audited all 27 command files — added Document Ripple and Test Verification steps to 15 commands that were missing them
59
+ - All code-modifying commands now enforce doc updates and test runs before completion
60
+
61
+ ## [2.4.0] - 2026-02-09
62
+
63
+ ### Added
64
+ - Automatic version bumping in `checkin` command — determines patch/minor/major from change type
65
+
66
+ ## [2.3.0] - 2026-02-09
67
+
68
+ ### Added
69
+ - Branch Guard — prevents commits on wrong branch by checking `Expected branch` in CLAUDE.md
70
+
71
+ ## [2.2.1] - 2026-02-09
72
+
73
+ ### Fixed
74
+ - `gsd-t-discuss` now stops for user review when manually invoked (was auto-continuing even in manual mode)
75
+
76
+ ## [2.2.0] - 2026-02-09
77
+
78
+ ### Added
79
+ - E2E test support in `test-sync`, `verify`, and `execute` commands
80
+
81
+ ## [2.1.0] - 2026-02-09
82
+
83
+ ### Added
84
+ - `gsd-t-populate` command — auto-populate living docs from existing codebase
85
+ - Semantic versioning system tracked in `progress.md`
86
+ - Auto-update README on version changes
87
+
88
+ ## [2.0.2] - 2026-02-07
89
+
90
+ ### Changed
91
+ - `gsd-t-init` now creates all 4 living document templates (`requirements.md`, `architecture.md`, `workflows.md`, `infrastructure.md`)
92
+ - `gsd-t-scan` cross-populates findings into living docs
93
+
94
+ ## [2.0.1] - 2026-02-07
95
+
96
+ ### Fixed
97
+ - Added `gsd-t-brainstorm` to all 4 reference files (README, GSD-T-README, CLAUDE-global, gsd-t-help)
98
+ - Fixed workflow diagram alignment
99
+
100
+ ## [2.0.0] - 2026-02-07
101
+
102
+ ### Added
103
+ - Renamed package to `@tekyzinc/gsd-t`
104
+ - `gsd-t-brainstorm` command — creative exploration, rethinking, and idea generation
105
+ - Initialized GSD-T state (`.gsd-t/` directory) on itself
106
+
107
+ ### Changed
108
+ - Complete framework rewrite from GSD to GSD-T (contract-driven development)
109
+ - npm package with CLI installer (`bin/gsd-t.js`)
110
+ - 6 CLI subcommands: install, update, init, status, doctor, uninstall
111
+
112
+ ## [1.0.0] - 2026-02-07
113
+
114
+ ### Added
115
+ - Initial GSD-T framework implementation
116
+ - Full milestone workflow: partition, discuss, plan, impact, execute, test-sync, integrate, verify, complete
117
+ - Agent Teams support for parallel execution
118
+ - Living documents system (requirements, architecture, workflows, infrastructure)
package/README.md CHANGED
@@ -72,6 +72,7 @@ npx @tekyzinc/gsd-t init [name] # Scaffold GSD-T project (auto-registers)
72
72
  npx @tekyzinc/gsd-t register # Register current directory as a GSD-T project
73
73
  npx @tekyzinc/gsd-t status # Check installation + version
74
74
  npx @tekyzinc/gsd-t doctor # Diagnose common issues
75
+ npx @tekyzinc/gsd-t changelog # Open changelog in the browser
75
76
  npx @tekyzinc/gsd-t uninstall # Remove commands (keeps project files)
76
77
  ```
77
78
 
package/bin/gsd-t.js CHANGED
@@ -12,11 +12,13 @@
12
12
  * npx @tekyzinc/gsd-t status — Show what's installed and check for updates
13
13
  * npx @tekyzinc/gsd-t uninstall — Remove GSD-T commands (leaves project files alone)
14
14
  * npx @tekyzinc/gsd-t doctor — Diagnose common issues
15
+ * npx @tekyzinc/gsd-t changelog — Open changelog in the browser
15
16
  */
16
17
 
17
18
  const fs = require("fs");
18
19
  const path = require("path");
19
20
  const os = require("os");
21
+ const { execSync } = require("child_process");
20
22
 
21
23
  // ─── Configuration ───────────────────────────────────────────────────────────
22
24
 
@@ -26,6 +28,7 @@ const GLOBAL_CLAUDE_MD = path.join(CLAUDE_DIR, "CLAUDE.md");
26
28
  const SETTINGS_JSON = path.join(CLAUDE_DIR, "settings.json");
27
29
  const VERSION_FILE = path.join(CLAUDE_DIR, ".gsd-t-version");
28
30
  const PROJECTS_FILE = path.join(CLAUDE_DIR, ".gsd-t-projects");
31
+ const UPDATE_CHECK_FILE = path.join(CLAUDE_DIR, ".gsd-t-update-check");
29
32
 
30
33
  // Where our package files live (relative to this script)
31
34
  const PKG_ROOT = path.resolve(__dirname, "..");
@@ -35,6 +38,7 @@ const PKG_EXAMPLES = path.join(PKG_ROOT, "examples");
35
38
 
36
39
  // Read our version from package.json
37
40
  const PKG_VERSION = require(path.join(PKG_ROOT, "package.json")).version;
41
+ const CHANGELOG_URL = "https://github.com/Tekyz-Inc/get-stuff-done-teams/blob/main/CHANGELOG.md";
38
42
 
39
43
  // ─── Helpers ─────────────────────────────────────────────────────────────────
40
44
 
@@ -64,6 +68,12 @@ function info(msg) {
64
68
  function heading(msg) {
65
69
  console.log(`\n${BOLD}${msg}${RESET}`);
66
70
  }
71
+ function link(text, url) {
72
+ return `\x1b]8;;${url}\x07${text}\x1b]8;;\x07`;
73
+ }
74
+ function versionLink(ver) {
75
+ return link(`v${ver || PKG_VERSION}`, CHANGELOG_URL);
76
+ }
67
77
 
68
78
  function ensureDir(dir) {
69
79
  if (!fs.existsSync(dir)) {
@@ -140,7 +150,7 @@ function doInstall(opts = {}) {
140
150
  const isUpdate = opts.update || false;
141
151
  const verb = isUpdate ? "Updating" : "Installing";
142
152
 
143
- heading(`${verb} GSD-T v${PKG_VERSION}`);
153
+ heading(`${verb} GSD-T ${versionLink()}`);
144
154
  log("");
145
155
 
146
156
  // 1. Create ~/.claude/commands/ if needed
@@ -224,7 +234,7 @@ function doInstall(opts = {}) {
224
234
  log("");
225
235
  log(` Commands: ${gsdtCommands.length} GSD-T + ${utilityCommands.length} utility commands in ~/.claude/commands/`);
226
236
  log(` Config: ~/.claude/CLAUDE.md`);
227
- log(` Version: ${PKG_VERSION}`);
237
+ log(` Version: ${versionLink()}`);
228
238
  log("");
229
239
  log(`${BOLD}Quick Start:${RESET}`);
230
240
  log(` ${DIM}$${RESET} cd your-project`);
@@ -245,7 +255,7 @@ function doUpdate() {
245
255
  const installedVersion = getInstalledVersion();
246
256
 
247
257
  if (installedVersion === PKG_VERSION) {
248
- heading(`GSD-T v${PKG_VERSION}`);
258
+ heading(`GSD-T ${versionLink()}`);
249
259
  info("Already up to date!");
250
260
  log("");
251
261
  log(" To force a reinstall, run:");
@@ -255,7 +265,7 @@ function doUpdate() {
255
265
  }
256
266
 
257
267
  if (installedVersion) {
258
- heading(`Updating GSD-T: v${installedVersion} → v${PKG_VERSION}`);
268
+ heading(`Updating GSD-T: ${versionLink(installedVersion)} → ${versionLink()}`);
259
269
  }
260
270
 
261
271
  doInstall({ update: true });
@@ -372,12 +382,12 @@ function doStatus() {
372
382
  // Installed version
373
383
  const installedVersion = getInstalledVersion();
374
384
  if (installedVersion) {
375
- success(`Installed version: ${installedVersion}`);
385
+ success(`Installed version: ${versionLink(installedVersion)}`);
376
386
  if (installedVersion !== PKG_VERSION) {
377
- warn(`Latest version: ${PKG_VERSION}`);
387
+ warn(`Latest version: ${versionLink()}`);
378
388
  info(`Run 'npx @tekyzinc/gsd-t update' to update`);
379
389
  } else {
380
- success(`Up to date (latest: ${PKG_VERSION})`);
390
+ success(`Up to date (latest: ${versionLink()})`);
381
391
  }
382
392
  } else {
383
393
  error("GSD-T not installed");
@@ -502,7 +512,7 @@ function doUpdateAll() {
502
512
  if (installedVersion !== PKG_VERSION) {
503
513
  doInstall({ update: true });
504
514
  } else {
505
- heading(`GSD-T v${PKG_VERSION}`);
515
+ heading(`GSD-T ${versionLink()}`);
506
516
  success("Global commands already up to date");
507
517
  }
508
518
 
@@ -531,6 +541,7 @@ function doUpdateAll() {
531
541
  for (const projectDir of projects) {
532
542
  const projectName = path.basename(projectDir);
533
543
  const claudeMd = path.join(projectDir, "CLAUDE.md");
544
+ let projectUpdated = false;
534
545
 
535
546
  // Check project still exists
536
547
  if (!fs.existsSync(projectDir)) {
@@ -548,56 +559,77 @@ function doUpdateAll() {
548
559
  const content = fs.readFileSync(claudeMd, "utf8");
549
560
 
550
561
  // Check if the project CLAUDE.md needs the Destructive Action Guard
551
- if (content.includes("Destructive Action Guard")) {
552
- info(`${projectName} already up to date`);
553
- skipped++;
554
- continue;
562
+ if (!content.includes("Destructive Action Guard")) {
563
+ const guardSection = [
564
+ "",
565
+ "",
566
+ "# Destructive Action Guard (MANDATORY)",
567
+ "",
568
+ "**NEVER perform destructive or structural changes without explicit user approval.** This applies at ALL autonomy levels.",
569
+ "",
570
+ "Before any of these actions, STOP and ask the user:",
571
+ "- DROP TABLE, DROP COLUMN, DROP INDEX, TRUNCATE, DELETE without WHERE",
572
+ "- Renaming or removing database tables or columns",
573
+ "- Schema migrations that lose data or break existing queries",
574
+ "- Replacing an existing architecture pattern (e.g., normalized → denormalized)",
575
+ "- Removing or replacing existing files/modules that contain working functionality",
576
+ "- Changing ORM models in ways that conflict with the existing database schema",
577
+ "- Removing API endpoints or changing response shapes that existing clients depend on",
578
+ "- Any change that would require other parts of the system to be rewritten",
579
+ "",
580
+ '**Rule: "Adapt new code to existing structures, not the other way around."**',
581
+ "",
582
+ ].join("\n");
583
+
584
+ let newContent;
585
+ const preCommitMatch = content.match(/\n(#{1,3} Pre-Commit Gate)/);
586
+ const dontDoMatch = content.match(/\n(#{1,3} Don't Do These Things)/);
587
+
588
+ if (preCommitMatch) {
589
+ newContent = content.replace(
590
+ "\n" + preCommitMatch[1],
591
+ guardSection + "\n" + preCommitMatch[1]
592
+ );
593
+ } else if (dontDoMatch) {
594
+ newContent = content.replace(
595
+ "\n" + dontDoMatch[1],
596
+ guardSection + "\n" + dontDoMatch[1]
597
+ );
598
+ } else {
599
+ newContent = content + guardSection;
600
+ }
601
+
602
+ fs.writeFileSync(claudeMd, newContent);
603
+ success(`${projectName} — added Destructive Action Guard`);
604
+ projectUpdated = true;
555
605
  }
556
606
 
557
- // Add the Destructive Action Guard section
558
- const guardSection = [
559
- "",
560
- "",
561
- "# Destructive Action Guard (MANDATORY)",
562
- "",
563
- "**NEVER perform destructive or structural changes without explicit user approval.** This applies at ALL autonomy levels.",
564
- "",
565
- "Before any of these actions, STOP and ask the user:",
566
- "- DROP TABLE, DROP COLUMN, DROP INDEX, TRUNCATE, DELETE without WHERE",
567
- "- Renaming or removing database tables or columns",
568
- "- Schema migrations that lose data or break existing queries",
569
- "- Replacing an existing architecture pattern (e.g., normalized → denormalized)",
570
- "- Removing or replacing existing files/modules that contain working functionality",
571
- "- Changing ORM models in ways that conflict with the existing database schema",
572
- "- Removing API endpoints or changing response shapes that existing clients depend on",
573
- "- Any change that would require other parts of the system to be rewritten",
574
- "",
575
- '**Rule: "Adapt new code to existing structures, not the other way around."**',
576
- "",
577
- ].join("\n");
578
-
579
- let newContent;
580
- // Match headings at any level (# or ## or ###)
581
- const preCommitMatch = content.match(/\n(#{1,3} Pre-Commit Gate)/);
582
- const dontDoMatch = content.match(/\n(#{1,3} Don't Do These Things)/);
583
-
584
- if (preCommitMatch) {
585
- newContent = content.replace(
586
- "\n" + preCommitMatch[1],
587
- guardSection + "\n" + preCommitMatch[1]
588
- );
589
- } else if (dontDoMatch) {
590
- newContent = content.replace(
591
- "\n" + dontDoMatch[1],
592
- guardSection + "\n" + dontDoMatch[1]
593
- );
594
- } else {
595
- newContent = content + guardSection;
607
+ // Create CHANGELOG.md if it doesn't exist
608
+ const changelogPath = path.join(projectDir, "CHANGELOG.md");
609
+ if (!fs.existsSync(changelogPath)) {
610
+ const today = new Date().toISOString().split("T")[0];
611
+ const changelogContent = [
612
+ "# Changelog",
613
+ "",
614
+ "All notable changes to this project are documented here.",
615
+ "",
616
+ `## [0.1.0] - ${today}`,
617
+ "",
618
+ "### Added",
619
+ "- Initial changelog created by GSD-T",
620
+ "",
621
+ ].join("\n");
622
+ fs.writeFileSync(changelogPath, changelogContent);
623
+ success(`${projectName} created CHANGELOG.md`);
624
+ projectUpdated = true;
596
625
  }
597
626
 
598
- fs.writeFileSync(claudeMd, newContent);
599
- success(`${projectName} — updated CLAUDE.md`);
600
- updated++;
627
+ if (projectUpdated) {
628
+ updated++;
629
+ } else {
630
+ info(`${projectName} — already up to date`);
631
+ skipped++;
632
+ }
601
633
  }
602
634
 
603
635
  // Summary
@@ -628,7 +660,6 @@ function doDoctor() {
628
660
  }
629
661
 
630
662
  // 2. Claude Code installed?
631
- const { execSync } = require("child_process");
632
663
  try {
633
664
  const claudeVersion = execSync("claude --version 2>&1", { encoding: "utf8" }).trim();
634
665
  success(`Claude Code: ${claudeVersion}`);
@@ -746,6 +777,75 @@ function doRegister() {
746
777
  log("");
747
778
  }
748
779
 
780
+ function checkForUpdates() {
781
+ // Skip check for update/install/update-all (they handle it themselves)
782
+ const skipCommands = ["install", "update", "update-all", "--version", "-v"];
783
+ if (skipCommands.includes(command)) return;
784
+
785
+ // Read cache (sync, fast)
786
+ let cached = null;
787
+ try {
788
+ if (fs.existsSync(UPDATE_CHECK_FILE)) {
789
+ cached = JSON.parse(fs.readFileSync(UPDATE_CHECK_FILE, "utf8"));
790
+ }
791
+ } catch { /* ignore corrupt cache */ }
792
+
793
+ // Show notice from cache if newer version is known
794
+ if (cached && cached.latest && cached.latest !== PKG_VERSION) {
795
+ showUpdateNotice(cached.latest);
796
+ }
797
+
798
+ // Refresh cache in background if stale (older than 24h) or missing
799
+ const isStale = !cached || (Date.now() - cached.timestamp) > 86400000;
800
+ if (isStale) {
801
+ const script = `
802
+ const https = require("https");
803
+ const fs = require("fs");
804
+ https.get("https://registry.npmjs.org/@tekyzinc/gsd-t/latest",
805
+ { timeout: 5000 }, (res) => {
806
+ let d = "";
807
+ res.on("data", (c) => d += c);
808
+ res.on("end", () => {
809
+ try {
810
+ const v = JSON.parse(d).version;
811
+ fs.writeFileSync(${JSON.stringify(UPDATE_CHECK_FILE)},
812
+ JSON.stringify({ latest: v, timestamp: Date.now() }));
813
+ } catch {}
814
+ });
815
+ }).on("error", () => {});
816
+ `.replace(/\n/g, "");
817
+ const { spawn } = require("child_process");
818
+ const child = spawn(process.execPath, ["-e", script], {
819
+ detached: true,
820
+ stdio: "ignore",
821
+ });
822
+ child.unref();
823
+ }
824
+ }
825
+
826
+ function showUpdateNotice(latest) {
827
+ log("");
828
+ log(` ${YELLOW}╭──────────────────────────────────────────────╮${RESET}`);
829
+ log(` ${YELLOW}│${RESET} Update available: ${DIM}${PKG_VERSION}${RESET} → ${GREEN}${latest}${RESET} ${YELLOW}│${RESET}`);
830
+ log(` ${YELLOW}│${RESET} Run: ${CYAN}npm update -g @tekyzinc/gsd-t${RESET} ${YELLOW}│${RESET}`);
831
+ log(` ${YELLOW}│${RESET} Then: ${CYAN}gsd-t update-all${RESET} ${YELLOW}│${RESET}`);
832
+ log(` ${YELLOW}│${RESET} Changelog: ${CYAN}gsd-t changelog${RESET} ${YELLOW}│${RESET}`);
833
+ log(` ${YELLOW}╰──────────────────────────────────────────────╯${RESET}`);
834
+ }
835
+
836
+ function doChangelog() {
837
+ const openCmd =
838
+ process.platform === "win32" ? "start" :
839
+ process.platform === "darwin" ? "open" : "xdg-open";
840
+ try {
841
+ execSync(`${openCmd} ${CHANGELOG_URL}`, { stdio: "ignore" });
842
+ success(`Opened changelog in browser`);
843
+ } catch {
844
+ // Fallback: print the URL
845
+ log(`\n ${CHANGELOG_URL}\n`);
846
+ }
847
+ }
848
+
749
849
  function showHelp() {
750
850
  log("");
751
851
  log(`${BOLD}GSD-T${RESET} — Contract-Driven Development for Claude Code`);
@@ -762,6 +862,7 @@ function showHelp() {
762
862
  log(` ${CYAN}status${RESET} Show installation status + check for updates`);
763
863
  log(` ${CYAN}uninstall${RESET} Remove GSD-T commands (keeps project files)`);
764
864
  log(` ${CYAN}doctor${RESET} Diagnose common issues`);
865
+ log(` ${CYAN}changelog${RESET} Open changelog in the browser`);
765
866
  log(` ${CYAN}help${RESET} Show this help`);
766
867
  log("");
767
868
  log(`${BOLD}Examples:${RESET}`);
@@ -807,6 +908,9 @@ switch (command) {
807
908
  case "doctor":
808
909
  doDoctor();
809
910
  break;
911
+ case "changelog":
912
+ doChangelog();
913
+ break;
810
914
  case "help":
811
915
  case "--help":
812
916
  case "-h":
@@ -821,3 +925,5 @@ switch (command) {
821
925
  showHelp();
822
926
  process.exit(1);
823
927
  }
928
+
929
+ checkForUpdates();
@@ -20,11 +20,18 @@ Automatically stage, commit, and push all updated files to GitHub with automatic
20
20
  8. Update the version in `package.json`
21
21
  9. If `.gsd-t/progress.md` exists, check for a `## Version` line and update it (or add one after the `## Date` line)
22
22
 
23
+ ### Release Notes
24
+
25
+ 10. If `CHANGELOG.md` exists in the project root, prepend an entry for this version:
26
+ - Use the format: `## [X.Y.Z] - YYYY-MM-DD` followed by `### Added`, `### Changed`, `### Fixed`, or `### Removed` subsections as appropriate
27
+ - Summarize the changes in 1-3 bullet points per subsection
28
+ - Place the new entry directly after the file header (before any existing version entries)
29
+
23
30
  ### Commit and Push
24
31
 
25
- 10. Stage all changes (including the version bump) with `git add -A`
26
- 11. Create a commit with a descriptive message summarizing the changes. Include `(vX.Y.Z)` at the end of the first line. Example: `fix: resolve branch guard edge case (v2.3.1)`
27
- 12. Push to origin with `git push`
28
- 13. Confirm success to the user, including the old → new version
32
+ 11. Stage all changes (including the version bump and changelog) with `git add -A`
33
+ 12. Create a commit with a descriptive message summarizing the changes. Include `(vX.Y.Z)` at the end of the first line. Example: `fix: resolve branch guard edge case (v2.3.1)`
34
+ 13. Push to origin with `git push`
35
+ 14. Confirm success to the user, including the old → new version
29
36
 
30
37
  Use the standard commit message format with Co-Authored-By line.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "2.9.0",
3
+ "version": "2.10.1",
4
4
  "description": "GSD-T: Contract-Driven Development for Claude Code — 35 slash commands with backlog management, impact analysis, test sync, and milestone archival",
5
5
  "author": "Tekyz, Inc.",
6
6
  "license": "MIT",
@@ -25,7 +25,8 @@
25
25
  "commands/",
26
26
  "templates/",
27
27
  "examples/",
28
- "docs/"
28
+ "docs/",
29
+ "CHANGELOG.md"
29
30
  ],
30
31
  "engines": {
31
32
  "node": ">=16.0.0"