jiradc-cli 1.0.18 → 1.0.19

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.
Files changed (3) hide show
  1. package/README.md +42 -6
  2. package/dist/index.js +208 -28
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -15,6 +15,12 @@ export JIRA_URL="https://jira.example.com" # Base URL of your Jira instance
15
15
  export JIRA_TOKEN="your-personal-access-token" # HTTP Access Token from Jira
16
16
  ```
17
17
 
18
+ ## Breaking changes in this release
19
+
20
+ - `issue transitions` now returns a bare JSON array of transitions (previously wrapped in `{ transitions: [...] }`). Each transition is reduced to `{ id, name, to, fields? }` — verbose fields like `to.iconUrl`, `to.statusCategory`, `isGlobal`, `isInitial`, `isConditional`, `hasScreen` are stripped.
21
+ - `component list` now requires `--project <key>` instead of a positional `<projectKey>` argument.
22
+ - `issue link-epic` is now variadic on the issue argument: `link-epic <issueKey...> --epic <epicKey>`. Single-issue calls keep working.
23
+
18
24
  ## Commands
19
25
 
20
26
  All commands output JSON. Add `--pretty` to pretty-print.
@@ -26,16 +32,17 @@ All commands output JSON. Add `--pretty` to pretty-print.
26
32
  | `jiradc issue get <key>` | Get issue details (`--fields` to select, `--expand` for changelog/transitions) |
27
33
  | `jiradc issue search <jql>` | Search issues with JQL |
28
34
  | `jiradc issue create` | Create an issue (`--project`, `--type`, `--summary`, `--description`, `--custom-fields`) |
29
- | `jiradc issue update <key>` | Update an issue |
35
+ | `jiradc issue update <key>` | Update an issue (`--summary`, `--description`, `--priority`, `--assignee`, `--labels`, `--components`, `--fix-versions`, or `--fields` JSON) |
30
36
  | `jiradc issue delete <key>` | Delete an issue |
31
- | `jiradc issue transition <key> <transitionId>` | Transition issue to a new status |
37
+ | `jiradc issue assign <key> <user>` | Assign issue (user can be a username, `me`, or `none` to unassign) |
38
+ | `jiradc issue transition <key>` | Transition issue to a new status (`--to` accepts ID or status name, `--comment` to add a note) |
32
39
  | `jiradc issue transitions <key>` | List available transitions |
33
40
  | `jiradc issue comment <key>` | Add a comment |
34
41
  | `jiradc issue comment-edit <key> <commentId>` | Edit a comment |
35
42
  | `jiradc issue link <key> <targetKey>` | Link two issues (`--type` link type name) |
36
43
  | `jiradc issue unlink <linkId>` | Remove a link |
37
44
  | `jiradc issue link-types` | List available link types |
38
- | `jiradc issue link-epic <epicKey> <issueKey>` | Link an issue to an epic |
45
+ | `jiradc issue link-epic <keys...>` | Link one or more issues to an epic (`--epic <epicKey>`) |
39
46
  | `jiradc issue worklog <key>` | Add a work log entry |
40
47
  | `jiradc issue get-worklog <key>` | Get work log entries |
41
48
  | `jiradc issue changelog <key>` | Get issue changelog |
@@ -60,7 +67,16 @@ All commands output JSON. Add `--pretty` to pretty-print.
60
67
  |---------|-------------|
61
68
  | `jiradc project list` | List projects |
62
69
  | `jiradc project versions <key>` | List versions for a project |
63
- | `jiradc project components <key>` | List components for a project |
70
+
71
+ ### component
72
+
73
+ | Command | Description |
74
+ |---------|-------------|
75
+ | `jiradc component list` | List components for a project (`--project <key>`) |
76
+ | `jiradc component get <id>` | Get a component by ID |
77
+ | `jiradc component create` | Create a component (`--project`, `--name`, `--description`, `--lead`) |
78
+ | `jiradc component update <id>` | Update a component |
79
+ | `jiradc component issue-count <id>` | Get the number of issues using a component |
64
80
 
65
81
  ### board
66
82
 
@@ -113,9 +129,26 @@ jiradc issue create --project AI --type Task --summary "Implement feature X" --d
113
129
  # Create with custom fields
114
130
  jiradc issue create --project AI --type Story --summary "User login" --custom-fields '{"customfield_10100": "value"}'
115
131
 
116
- # Transition an issue (find transition ID first)
132
+ # Transition by ID or by status name
117
133
  jiradc issue transitions AI-123
118
- jiradc issue transition AI-123 31
134
+ jiradc issue transition AI-123 --to 31
135
+ jiradc issue transition AI-123 --to "In Review" --comment "Ready for review"
136
+
137
+ # Assign
138
+ jiradc issue assign AI-123 me
139
+ jiradc issue assign AI-123 jsmith
140
+ jiradc issue assign AI-123 none
141
+
142
+ # Update with shortcuts (instead of --fields JSON)
143
+ jiradc issue update AI-123 --summary "New title" --priority High
144
+ jiradc issue update AI-123 --assignee me
145
+ jiradc issue update AI-123 --labels backend,urgent # set mode
146
+ jiradc issue update AI-123 --labels +urgent,-backend # mutate mode
147
+ jiradc issue update AI-123 --components +Frontend
148
+ jiradc issue update AI-123 --fix-versions 1.0,2.0
149
+
150
+ # Link multiple issues to an epic in one call
151
+ jiradc issue link-epic AI-456 AI-457 AI-458 --epic AI-100
119
152
 
120
153
  # Add a comment
121
154
  jiradc issue comment AI-123 --body "Fixed in commit abc123"
@@ -140,4 +173,7 @@ jiradc issue clone AI-123
140
173
 
141
174
  # Get dev status (linked branches, PRs)
142
175
  jiradc issue dev-status AI-123
176
+
177
+ # List components for a project
178
+ jiradc component list --project AI
143
179
  ```
package/dist/index.js CHANGED
@@ -432,6 +432,22 @@ function transformIssueFields(fields) {
432
432
  };
433
433
  }
434
434
 
435
+ // src/utils/transformers/transition.ts
436
+ function transformTransition(t) {
437
+ const out = {
438
+ id: t.id,
439
+ name: t.name,
440
+ to: t.to.name
441
+ };
442
+ if (t.fields && Object.keys(t.fields).length > 0) {
443
+ out.fields = t.fields;
444
+ }
445
+ return out;
446
+ }
447
+ function transformTransitions(response) {
448
+ return response.transitions.map(transformTransition);
449
+ }
450
+
435
451
  // src/commands/board/issues.ts
436
452
  function issues(parent) {
437
453
  parent.command("issues").description("Get issues for a board").addArgument(new Argument("<id>", "Board ID").argParser(positiveInt)).option("--limit <number>", "Max results (1-50, Jira DC caps at 50)", intInRange(1, 50), 25).option("--start <number>", "Starting index for pagination", nonNegativeInt).option("--fields <fields>", "Comma-separated field names to return").option("--jql <jql>", "Additional JQL filter within the board").addHelpText(
@@ -550,9 +566,9 @@ function issueCount(parent) {
550
566
 
551
567
  // src/commands/component/list.ts
552
568
  function list2(parent) {
553
- parent.command("list <projectKey>").description("List all components for a project").addHelpText("after", "\nExamples:\n jiradc component list AI").action(async (projectKey) => {
569
+ parent.command("list").description("List all components for a project").requiredOption("--project <key>", "Project key (e.g., AI)").addHelpText("after", "\nExamples:\n jiradc component list --project AI").action(async (opts) => {
554
570
  const client = getClient();
555
- const result = await client.components.list({ projectKeyOrId: projectKey });
571
+ const result = await client.components.list({ projectKeyOrId: opts.project });
556
572
  output(result.map(transformComponent));
557
573
  });
558
574
  }
@@ -597,7 +613,7 @@ function registerComponentCommands(program2) {
597
613
  "after",
598
614
  `
599
615
  Examples:
600
- $ jiradc component list AI
616
+ $ jiradc component list --project AI
601
617
  $ jiradc component get 11289
602
618
  $ jiradc component create --project AI --name Backend
603
619
  $ jiradc component update 11289 --name Backend
@@ -657,6 +673,42 @@ Examples:
657
673
  options(field);
658
674
  }
659
675
 
676
+ // src/utils/resolve-user.ts
677
+ var cachedMe;
678
+ async function resolveUserToken(token) {
679
+ if (token === "none") return null;
680
+ if (token === "me") {
681
+ if (cachedMe !== void 0) return cachedMe;
682
+ const me2 = await getClient().users.getMyself();
683
+ if (!me2.name) {
684
+ throw new Error('Could not resolve "me": authenticated user has no name field');
685
+ }
686
+ cachedMe = me2.name;
687
+ return cachedMe;
688
+ }
689
+ return token;
690
+ }
691
+
692
+ // src/commands/issue/assign.ts
693
+ function assign(parent) {
694
+ parent.command("assign <key> <user>").description('Assign an issue. <user> is a username, "me", or "none" to unassign.').addHelpText(
695
+ "after",
696
+ `
697
+ Examples:
698
+ jiradc issue assign PROJ-123 jsmith
699
+ jiradc issue assign PROJ-123 me
700
+ jiradc issue assign PROJ-123 none`
701
+ ).action(async (key, user) => {
702
+ const resolved = await resolveUserToken(user);
703
+ const client = getClient();
704
+ await client.issues.update({
705
+ issueKeyOrId: key,
706
+ fields: { assignee: resolved === null ? null : { name: resolved } }
707
+ });
708
+ output({ assigned: true, issue: transformIssueRef(key), assignee: resolved });
709
+ });
710
+ }
711
+
660
712
  // src/commands/issue/attachment/delete.ts
661
713
  function deleteAttachment(parent) {
662
714
  parent.command("delete").description("Delete an attachment by ID").requiredOption("--id <attachmentId>", "Attachment ID to delete").addHelpText("after", "\nExamples:\n jiradc issue attachment delete --id 12345").action(async (opts) => {
@@ -1185,17 +1237,37 @@ function get2(parent) {
1185
1237
 
1186
1238
  // src/commands/issue/link-epic.ts
1187
1239
  function linkEpic(parent) {
1188
- parent.command("link-epic <key>").description("Link an issue to an epic").requiredOption("--epic <epicKey>", "Epic issue key").addHelpText("after", "\nExamples:\n jiradc issue link-epic PROJ-456 --epic PROJ-123").action(async (key, opts) => {
1240
+ parent.command("link-epic <keys...>").description("Link one or more issues to an epic").requiredOption("--epic <epicKey>", "Epic issue key").addHelpText(
1241
+ "after",
1242
+ `
1243
+ Examples:
1244
+ jiradc issue link-epic PROJ-456 --epic PROJ-123
1245
+ jiradc issue link-epic PROJ-456 PROJ-457 PROJ-458 --epic PROJ-123`
1246
+ ).action(async (keys, opts) => {
1189
1247
  const client = getClient();
1190
- await client.issues.update({
1191
- issueKeyOrId: key,
1192
- fields: { customfield_10100: opts.epic }
1248
+ const results = await Promise.allSettled(
1249
+ keys.map(
1250
+ (key) => client.issues.update({ issueKeyOrId: key, fields: { customfield_10100: opts.epic } }).then(() => key)
1251
+ )
1252
+ );
1253
+ const linked = [];
1254
+ const failed = [];
1255
+ results.forEach((r, i) => {
1256
+ if (r.status === "fulfilled") {
1257
+ linked.push({ key: r.value });
1258
+ } else {
1259
+ const message = r.reason instanceof Error ? r.reason.message : String(r.reason);
1260
+ failed.push({ key: keys[i], error: message });
1261
+ }
1193
1262
  });
1194
1263
  output({
1195
- linked: true,
1196
- issue: transformIssueRef(key),
1197
- epic: transformIssueRef(opts.epic)
1264
+ epic: transformIssueRef(opts.epic),
1265
+ linked,
1266
+ ...failed.length > 0 && { failed }
1198
1267
  });
1268
+ if (failed.length > 0) {
1269
+ process.exitCode = 1;
1270
+ }
1199
1271
  });
1200
1272
  }
1201
1273
 
@@ -1250,12 +1322,37 @@ function search2(parent) {
1250
1322
 
1251
1323
  // src/commands/issue/transition.ts
1252
1324
  function transition(parent) {
1253
- parent.command("transition <key>").description("Transition issue to a new status").requiredOption("--to <id>", 'Transition ID (get from "jiradc issue transitions")').option("--comment <text>", "Comment to add during transition").addHelpText(
1325
+ parent.command("transition <key>").description("Transition issue to a new status").requiredOption("--to <idOrName>", "Transition ID, or status name (case-insensitive)").option("--comment <text>", "Comment to add during transition").addHelpText(
1254
1326
  "after",
1255
- '\nExamples:\n jiradc issue transition PROJ-123 --to 31\n jiradc issue transition PROJ-123 --to 31 --comment "Moving to review"'
1327
+ `
1328
+ Examples:
1329
+ jiradc issue transition PROJ-123 --to 31
1330
+ jiradc issue transition PROJ-123 --to "In Review"
1331
+ jiradc issue transition PROJ-123 --to Done --comment "Verified in staging"`
1256
1332
  ).action(async (key, opts) => {
1257
1333
  const client = getClient();
1258
- await client.issues.transition({ issueKeyOrId: key, transitionId: opts.to, comment: opts.comment });
1334
+ let transitionId;
1335
+ if (/^\d+$/.test(opts.to)) {
1336
+ transitionId = opts.to;
1337
+ } else {
1338
+ const raw = await client.issues.getTransitions({
1339
+ issueKeyOrId: key,
1340
+ expand: "transitions.fields"
1341
+ });
1342
+ const transitions2 = transformTransitions(raw);
1343
+ const target = opts.to.toLowerCase();
1344
+ const matches = transitions2.filter((t) => t.name.toLowerCase() === target);
1345
+ if (matches.length === 0) {
1346
+ const names = transitions2.map((t) => `"${t.name}"`).join(", ");
1347
+ throw new Error(`Transition "${opts.to}" not available from current status. Available: ${names || "(none)"}`);
1348
+ }
1349
+ if (matches.length > 1) {
1350
+ const ids = matches.map((t) => t.id).join(", ");
1351
+ throw new Error(`Multiple transitions named "${opts.to}". Use --to <id> with one of: ${ids}`);
1352
+ }
1353
+ transitionId = matches[0].id;
1354
+ }
1355
+ await client.issues.transition({ issueKeyOrId: key, transitionId, comment: opts.comment });
1259
1356
  output({ transitioned: true, issue: transformIssueRef(key) });
1260
1357
  });
1261
1358
  }
@@ -1264,8 +1361,11 @@ function transition(parent) {
1264
1361
  function transitions(parent) {
1265
1362
  parent.command("transitions <key>").description("Get available transitions for an issue").addHelpText("after", "\nExamples:\n jiradc issue transitions PROJ-123").action(async (key) => {
1266
1363
  const client = getClient();
1267
- const result = await client.issues.getTransitions({ issueKeyOrId: key });
1268
- output(result);
1364
+ const result = await client.issues.getTransitions({
1365
+ issueKeyOrId: key,
1366
+ expand: "transitions.fields"
1367
+ });
1368
+ output(transformTransitions(result));
1269
1369
  });
1270
1370
  }
1271
1371
 
@@ -1278,24 +1378,103 @@ function unlink2(parent) {
1278
1378
  });
1279
1379
  }
1280
1380
 
1381
+ // src/utils/multi-value.ts
1382
+ import { InvalidArgumentError as InvalidArgumentError2 } from "commander";
1383
+ function parseMultiValue(flagName, raw) {
1384
+ const items = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
1385
+ if (items.length === 0) {
1386
+ throw new InvalidArgumentError2(`${flagName} cannot be empty`);
1387
+ }
1388
+ const lonePrefix = items.find((s) => s === "+" || s === "-");
1389
+ if (lonePrefix !== void 0) {
1390
+ throw new InvalidArgumentError2(`${flagName} has an empty value after '${lonePrefix}' prefix`);
1391
+ }
1392
+ const prefixed = items.filter((s) => s.startsWith("+") || s.startsWith("-"));
1393
+ const bare = items.filter((s) => !s.startsWith("+") && !s.startsWith("-"));
1394
+ if (prefixed.length > 0 && bare.length > 0) {
1395
+ throw new InvalidArgumentError2(
1396
+ `${flagName} mixes set and mutate syntax. Either all values have +/- prefix, or none do.`
1397
+ );
1398
+ }
1399
+ if (bare.length > 0) {
1400
+ return { mode: "set", values: bare };
1401
+ }
1402
+ const adds = prefixed.filter((s) => s.startsWith("+")).map((s) => s.slice(1));
1403
+ const removes = prefixed.filter((s) => s.startsWith("-")).map((s) => s.slice(1));
1404
+ return { mode: "mutate", adds, removes };
1405
+ }
1406
+
1281
1407
  // src/commands/issue/update.ts
1408
+ function buildUpdateOps(parsed, wrap) {
1409
+ if (parsed.mode !== "mutate") return void 0;
1410
+ return [...parsed.adds.map((v) => ({ add: wrap(v) })), ...parsed.removes.map((v) => ({ remove: wrap(v) }))];
1411
+ }
1412
+ function buildSetValue(parsed, wrap) {
1413
+ if (parsed.mode !== "set") return void 0;
1414
+ return parsed.values.map(wrap);
1415
+ }
1282
1416
  function update2(parent) {
1283
- parent.command("update <key>").description("Update issue fields").option("--fields <json>", "JSON string of fields to update").option("--notify-users", "Notify users about the update (default: true)").option("--attachments <paths>", "Comma-separated local file paths to attach").addHelpText(
1417
+ parent.command("update <key>").description("Update issue fields").option("--fields <json>", "JSON string of fields to update (advanced; merges with shortcuts, wins on conflict)").option("--no-notify-users", "Suppress notification emails (default: notify)").option("--attachments <paths>", "Comma-separated local file paths to attach").option("--summary <text>", "Set the issue summary").option("--description <text>", "Set the issue description (wiki markup)").option("--priority <name>", "Set the priority by name (e.g. High)").option("--assignee <user>", 'Set the assignee. Username, "me", or "none" to unassign.').option("--labels <list>", 'Set labels ("a,b,c") or mutate ("+add,-remove")').option("--components <list>", 'Set components ("a,b") or mutate ("+add,-remove")').option("--fix-versions <list>", 'Set fix versions ("1.0,2.0") or mutate ("+1.0,-0.9")').addHelpText(
1284
1418
  "after",
1285
1419
  `
1286
1420
  Examples:
1287
- jiradc issue update PROJ-123 --fields '{"summary": "New title"}'
1288
- jiradc issue update PROJ-123 --fields '{"assignee": {"name": "jsmith"}, "priority": {"name": "High"}}'
1289
- jiradc issue update PROJ-123 --attachments /path/to/file.pdf,/path/to/image.png
1290
- jiradc issue update PROJ-123 --fields '{"summary": "With attachment"}' --attachments ./report.pdf`
1421
+ jiradc issue update PROJ-123 --summary "New title"
1422
+ jiradc issue update PROJ-123 --priority High --assignee me
1423
+ jiradc issue update PROJ-123 --labels backend,urgent
1424
+ jiradc issue update PROJ-123 --labels +urgent,-backend
1425
+ jiradc issue update PROJ-123 --components +Frontend
1426
+ jiradc issue update PROJ-123 --fields '{"customfield_10100": "EPIC-1"}' --priority High
1427
+ jiradc issue update PROJ-123 --attachments /path/to/file.pdf,/path/to/image.png`
1291
1428
  ).action(async (key, opts) => {
1292
- if (!opts.fields && !opts.attachments) {
1293
- throw new Error("Provide --fields and/or --attachments");
1429
+ const hasShortcut = opts.summary !== void 0 || opts.description !== void 0 || opts.priority !== void 0 || opts.assignee !== void 0 || opts.labels !== void 0 || opts.components !== void 0 || opts.fixVersions !== void 0;
1430
+ if (!opts.fields && !opts.attachments && !hasShortcut) {
1431
+ throw new Error(
1432
+ "Provide at least one of --fields, --attachments, or a shortcut flag (--summary, --priority, --labels, ...)"
1433
+ );
1434
+ }
1435
+ const fields = {};
1436
+ const updateOps = {};
1437
+ if (opts.summary !== void 0) fields.summary = opts.summary;
1438
+ if (opts.description !== void 0) fields.description = opts.description;
1439
+ if (opts.priority !== void 0) fields.priority = { name: opts.priority };
1440
+ if (opts.assignee !== void 0) {
1441
+ const resolved = await resolveUserToken(opts.assignee);
1442
+ fields.assignee = resolved === null ? null : { name: resolved };
1443
+ }
1444
+ if (opts.labels !== void 0) {
1445
+ const parsed = parseMultiValue("--labels", opts.labels);
1446
+ const setVal = buildSetValue(parsed, (v) => v);
1447
+ const ops = buildUpdateOps(parsed, (v) => v);
1448
+ if (setVal) fields.labels = setVal;
1449
+ if (ops) updateOps.labels = ops;
1450
+ }
1451
+ if (opts.components !== void 0) {
1452
+ const parsed = parseMultiValue("--components", opts.components);
1453
+ const setVal = buildSetValue(parsed, (v) => ({ name: v }));
1454
+ const ops = buildUpdateOps(parsed, (v) => ({ name: v }));
1455
+ if (setVal) fields.components = setVal;
1456
+ if (ops) updateOps.components = ops;
1457
+ }
1458
+ if (opts.fixVersions !== void 0) {
1459
+ const parsed = parseMultiValue("--fix-versions", opts.fixVersions);
1460
+ const setVal = buildSetValue(parsed, (v) => ({ name: v }));
1461
+ const ops = buildUpdateOps(parsed, (v) => ({ name: v }));
1462
+ if (setVal) fields.fixVersions = setVal;
1463
+ if (ops) updateOps.fixVersions = ops;
1294
1464
  }
1295
- const client = getClient();
1296
1465
  if (opts.fields) {
1297
- const parsed = JSON.parse(opts.fields);
1298
- await client.issues.update({ issueKeyOrId: key, fields: parsed, notifyUsers: opts.notifyUsers });
1466
+ const parsedFields = JSON.parse(opts.fields);
1467
+ Object.assign(fields, parsedFields);
1468
+ }
1469
+ const client = getClient();
1470
+ const didFieldUpdate = Object.keys(fields).length > 0 || Object.keys(updateOps).length > 0;
1471
+ if (didFieldUpdate) {
1472
+ await client.issues.update({
1473
+ issueKeyOrId: key,
1474
+ fields: Object.keys(fields).length > 0 ? fields : void 0,
1475
+ update: Object.keys(updateOps).length > 0 ? updateOps : void 0,
1476
+ notifyUsers: opts.notifyUsers
1477
+ });
1299
1478
  }
1300
1479
  const uploaded = [];
1301
1480
  if (opts.attachments) {
@@ -1308,9 +1487,9 @@ Examples:
1308
1487
  }
1309
1488
  }
1310
1489
  output({
1311
- updated: true,
1312
- issue: transformIssueRef(key),
1313
- ...uploaded.length > 0 && { attachments: uploaded }
1490
+ ...didFieldUpdate && { updated: true },
1491
+ ...uploaded.length > 0 && { attached: true, attachments: uploaded },
1492
+ issue: transformIssueRef(key)
1314
1493
  });
1315
1494
  });
1316
1495
  }
@@ -1353,6 +1532,7 @@ Examples:
1353
1532
  deleteIssue(issue);
1354
1533
  transition(issue);
1355
1534
  transitions(issue);
1535
+ assign(issue);
1356
1536
  comment(issue);
1357
1537
  commentEdit(issue);
1358
1538
  worklog(issue);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jiradc-cli",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
4
  "publish": true,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,7 +12,7 @@
12
12
  ],
13
13
  "dependencies": {
14
14
  "commander": "^13.1.0",
15
- "jira-data-center-client": "1.0.35"
15
+ "jira-data-center-client": "1.0.36"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/node": "24.10.4",
@@ -22,8 +22,8 @@
22
22
  "tsx": "^4.19.2",
23
23
  "typescript": "^5.7.2",
24
24
  "vitest": "^4.0.16",
25
- "config-typescript": "0.0.0",
26
- "config-eslint": "0.0.0"
25
+ "config-eslint": "0.0.0",
26
+ "config-typescript": "0.0.0"
27
27
  },
28
28
  "engines": {
29
29
  "node": ">=22.0.0"