hcent 0.1.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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -0
  3. package/dist/agent/context-manager.d.ts +14 -0
  4. package/dist/agent/context-manager.js +109 -0
  5. package/dist/agent/context-manager.js.map +1 -0
  6. package/dist/agent/index.d.ts +27 -0
  7. package/dist/agent/index.js +120 -0
  8. package/dist/agent/index.js.map +1 -0
  9. package/dist/bin.d.ts +2 -0
  10. package/dist/bin.js +40 -0
  11. package/dist/bin.js.map +1 -0
  12. package/dist/config/index.d.ts +25 -0
  13. package/dist/config/index.js +109 -0
  14. package/dist/config/index.js.map +1 -0
  15. package/dist/main.d.ts +1 -0
  16. package/dist/main.js +43 -0
  17. package/dist/main.js.map +1 -0
  18. package/dist/provider/index.d.ts +23 -0
  19. package/dist/provider/index.js +124 -0
  20. package/dist/provider/index.js.map +1 -0
  21. package/dist/provider/provider-manager.d.ts +9 -0
  22. package/dist/provider/provider-manager.js +43 -0
  23. package/dist/provider/provider-manager.js.map +1 -0
  24. package/dist/session/index.d.ts +39 -0
  25. package/dist/session/index.js +69 -0
  26. package/dist/session/index.js.map +1 -0
  27. package/dist/session/session-store.d.ts +19 -0
  28. package/dist/session/session-store.js +109 -0
  29. package/dist/session/session-store.js.map +1 -0
  30. package/dist/setup/index.d.ts +11 -0
  31. package/dist/setup/index.js +97 -0
  32. package/dist/setup/index.js.map +1 -0
  33. package/dist/skill/command-palette.d.ts +12 -0
  34. package/dist/skill/command-palette.js +62 -0
  35. package/dist/skill/command-palette.js.map +1 -0
  36. package/dist/skill/index.d.ts +15 -0
  37. package/dist/skill/index.js +145 -0
  38. package/dist/skill/index.js.map +1 -0
  39. package/dist/skill/skill-pointer.d.ts +18 -0
  40. package/dist/skill/skill-pointer.js +70 -0
  41. package/dist/skill/skill-pointer.js.map +1 -0
  42. package/dist/tools/index.d.ts +26 -0
  43. package/dist/tools/index.js +745 -0
  44. package/dist/tools/index.js.map +1 -0
  45. package/dist/tools/permission.d.ts +11 -0
  46. package/dist/tools/permission.js +11 -0
  47. package/dist/tools/permission.js.map +1 -0
  48. package/dist/tui/aligned-text.d.ts +14 -0
  49. package/dist/tui/aligned-text.js +46 -0
  50. package/dist/tui/aligned-text.js.map +1 -0
  51. package/dist/tui/builtin-commands.d.ts +40 -0
  52. package/dist/tui/builtin-commands.js +137 -0
  53. package/dist/tui/builtin-commands.js.map +1 -0
  54. package/dist/tui/editor-history.d.ts +6 -0
  55. package/dist/tui/editor-history.js +11 -0
  56. package/dist/tui/editor-history.js.map +1 -0
  57. package/dist/tui/editor-placeholder.d.ts +2 -0
  58. package/dist/tui/editor-placeholder.js +16 -0
  59. package/dist/tui/editor-placeholder.js.map +1 -0
  60. package/dist/tui/editor-with-placeholder.d.ts +8 -0
  61. package/dist/tui/editor-with-placeholder.js +49 -0
  62. package/dist/tui/editor-with-placeholder.js.map +1 -0
  63. package/dist/tui/hcent-autocomplete.d.ts +19 -0
  64. package/dist/tui/hcent-autocomplete.js +63 -0
  65. package/dist/tui/hcent-autocomplete.js.map +1 -0
  66. package/dist/tui/help-text.d.ts +1 -0
  67. package/dist/tui/help-text.js +15 -0
  68. package/dist/tui/help-text.js.map +1 -0
  69. package/dist/tui/index.d.ts +18 -0
  70. package/dist/tui/index.js +520 -0
  71. package/dist/tui/index.js.map +1 -0
  72. package/dist/tui/message-display.d.ts +8 -0
  73. package/dist/tui/message-display.js +41 -0
  74. package/dist/tui/message-display.js.map +1 -0
  75. package/dist/tui/pi-themes.d.ts +4 -0
  76. package/dist/tui/pi-themes.js +30 -0
  77. package/dist/tui/pi-themes.js.map +1 -0
  78. package/dist/tui/render-message.d.ts +3 -0
  79. package/dist/tui/render-message.js +32 -0
  80. package/dist/tui/render-message.js.map +1 -0
  81. package/dist/tui/thinking-loader.d.ts +17 -0
  82. package/dist/tui/thinking-loader.js +108 -0
  83. package/dist/tui/thinking-loader.js.map +1 -0
  84. package/dist/tui/user-message.d.ts +12 -0
  85. package/dist/tui/user-message.js +35 -0
  86. package/dist/tui/user-message.js.map +1 -0
  87. package/package.json +75 -0
@@ -0,0 +1,32 @@
1
+ import chalk from 'chalk';
2
+ import { Container, Markdown, Text } from '@earendil-works/pi-tui';
3
+ import { assistantHasDisplayContent, isMessageVisible, toolCallSummary, truncateDisplay, } from './message-display.js';
4
+ import { UserMessage, formatAssistantMessage } from './user-message.js';
5
+ function renderAssistantWithTools(m, activeId, mdTheme) {
6
+ const container = new Container();
7
+ if (assistantHasDisplayContent(m.content)) {
8
+ container.addChild(new Markdown(formatAssistantMessage(m.content), 1, 0, mdTheme));
9
+ }
10
+ for (const tc of m.toolCalls ?? []) {
11
+ const dot = chalk.yellow('⏺');
12
+ const line = `${dot} ${chalk.magenta(tc.name)}(${toolCallSummary(tc.name, tc.arguments)})`;
13
+ container.addChild(new Text(line, 1, 0));
14
+ }
15
+ return container;
16
+ }
17
+ export function renderMessageComponent(m, activeId, mdTheme) {
18
+ if (!isMessageVisible(m))
19
+ return null;
20
+ if (m.role === 'tool') {
21
+ return new Text(chalk.red(` ✗ ${truncateDisplay(m.content)}`), 1, 0);
22
+ }
23
+ if (m.role === 'assistant' && m.toolCalls && m.toolCalls.length > 0) {
24
+ return renderAssistantWithTools(m, activeId, mdTheme);
25
+ }
26
+ if (m.role === 'user')
27
+ return new UserMessage(m.content);
28
+ if (m.role === 'system')
29
+ return new Text(chalk.gray(m.content), 1, 0);
30
+ return new Markdown(formatAssistantMessage(m.content), 1, 0, mdTheme);
31
+ }
32
+ //# sourceMappingURL=render-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-message.js","sourceRoot":"","sources":["../../src/tui/render-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAsC,MAAM,wBAAwB,CAAC;AAEvG,OAAO,EACL,0BAA0B,EAC1B,gBAAgB,EAChB,eAAe,EACf,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAExE,SAAS,wBAAwB,CAC/B,CAAU,EACV,QAAuB,EACvB,OAAsB;IAEtB,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;IAClC,IAAI,0BAA0B,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1C,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACrF,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC;QAC3F,SAAS,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,CAAU,EACV,QAAuB,EACvB,OAAsB;IAEtB,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpE,OAAO,wBAAwB,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACzD,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,OAAO,IAAI,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AACxE,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { Loader, type TUI } from '@earendil-works/pi-tui';
2
+ export declare const THINKING_PHRASES: readonly ["等等等等等等等等", "别催别催,快了快了", "先别急,哥们", "知道你很急,但你先别急", "稍等,等我想想…", "让我琢磨一下…", "稍等,理一理思路…", "让我想想怎么说…", "先想一下哈…", "想了想,马上来…", "思考中,稍候…", "让我好好想想…", "稍等片刻…", "在想,快了…", "稍等,脑子转一圈…", "等等,容我思考一下…", "让我认真想想…", "稍等,整理一下思路…", "嗯,想一想再说…", "好,让我先想想…"];
3
+ export declare const THINKING_PHRASE_MS = 3000;
4
+ export declare const THINKING_SHIMMER_MS = 100;
5
+ export declare function pickThinkingPhrase(exclude?: string): string;
6
+ /** 光标扫光:高亮头 + 渐隐尾,其余 dim */
7
+ export declare function formatShimmerMessage(text: string, sweepIndex: number): string;
8
+ export interface ThinkingLoaderCallbacks {
9
+ onPhraseChange?: (phrase: string) => void;
10
+ }
11
+ export interface ThinkingLoaderController {
12
+ loader: Loader;
13
+ start(): void;
14
+ stop(): void;
15
+ currentPhrase: string;
16
+ }
17
+ export declare function createThinkingLoader(tui: TUI, callbacks?: ThinkingLoaderCallbacks): ThinkingLoaderController;
@@ -0,0 +1,108 @@
1
+ import { Chalk } from 'chalk';
2
+ import { Loader } from '@earendil-works/pi-tui';
3
+ const chalk = new Chalk({ level: 3 });
4
+ export const THINKING_PHRASES = [
5
+ '等等等等等等等等',
6
+ '别催别催,快了快了',
7
+ '先别急,哥们',
8
+ '知道你很急,但你先别急',
9
+ '稍等,等我想想…',
10
+ '让我琢磨一下…',
11
+ '稍等,理一理思路…',
12
+ '让我想想怎么说…',
13
+ '先想一下哈…',
14
+ '想了想,马上来…',
15
+ '思考中,稍候…',
16
+ '让我好好想想…',
17
+ '稍等片刻…',
18
+ '在想,快了…',
19
+ '稍等,脑子转一圈…',
20
+ '等等,容我思考一下…',
21
+ '让我认真想想…',
22
+ '稍等,整理一下思路…',
23
+ '嗯,想一想再说…',
24
+ '好,让我先想想…',
25
+ ];
26
+ const BRAILLE_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
27
+ const SPINNER_COLORS = [
28
+ (s) => chalk.cyan(s),
29
+ (s) => chalk.blue(s),
30
+ (s) => chalk.magenta(s),
31
+ (s) => chalk.yellow(s),
32
+ (s) => chalk.green(s),
33
+ (s) => chalk.red(s),
34
+ ];
35
+ const SHIMMER_TRAIL = [
36
+ (s) => chalk.bold.white(s),
37
+ (s) => chalk.cyan.bold(s),
38
+ (s) => chalk.blue(s),
39
+ ];
40
+ export const THINKING_PHRASE_MS = 3000;
41
+ export const THINKING_SHIMMER_MS = 100;
42
+ export function pickThinkingPhrase(exclude) {
43
+ const pool = exclude
44
+ ? THINKING_PHRASES.filter((p) => p !== exclude)
45
+ : [...THINKING_PHRASES];
46
+ return pool[Math.floor(Math.random() * pool.length)] ?? THINKING_PHRASES[0];
47
+ }
48
+ /** 光标扫光:高亮头 + 渐隐尾,其余 dim */
49
+ export function formatShimmerMessage(text, sweepIndex) {
50
+ if (text.length === 0)
51
+ return chalk.dim(text);
52
+ const len = text.length;
53
+ const head = ((sweepIndex % len) + len) % len;
54
+ return [...text].map((ch, i) => {
55
+ const dist = (head - i + len) % len;
56
+ if (dist < SHIMMER_TRAIL.length)
57
+ return SHIMMER_TRAIL[dist](ch);
58
+ return chalk.dim(ch);
59
+ }).join('');
60
+ }
61
+ function buildColorfulSpinnerFrames() {
62
+ return BRAILLE_FRAMES.map((frame, i) => SPINNER_COLORS[i % SPINNER_COLORS.length](frame));
63
+ }
64
+ export function createThinkingLoader(tui, callbacks) {
65
+ let currentPhrase = pickThinkingPhrase();
66
+ let sweepIndex = 0;
67
+ let phraseTimer = null;
68
+ let shimmerTimer = null;
69
+ const loader = new Loader(tui, (s) => s, (msg) => formatShimmerMessage(msg, sweepIndex), currentPhrase, { frames: buildColorfulSpinnerFrames(), intervalMs: 80 });
70
+ const refreshDisplay = () => {
71
+ loader.setMessage(currentPhrase);
72
+ };
73
+ const rotatePhrase = () => {
74
+ currentPhrase = pickThinkingPhrase(currentPhrase);
75
+ sweepIndex = 0;
76
+ refreshDisplay();
77
+ callbacks?.onPhraseChange?.(currentPhrase);
78
+ };
79
+ return {
80
+ loader,
81
+ get currentPhrase() {
82
+ return currentPhrase;
83
+ },
84
+ start() {
85
+ sweepIndex = 0;
86
+ refreshDisplay();
87
+ loader.start();
88
+ shimmerTimer = setInterval(() => {
89
+ sweepIndex++;
90
+ refreshDisplay();
91
+ }, THINKING_SHIMMER_MS);
92
+ phraseTimer = setInterval(rotatePhrase, THINKING_PHRASE_MS);
93
+ callbacks?.onPhraseChange?.(currentPhrase);
94
+ },
95
+ stop() {
96
+ if (shimmerTimer) {
97
+ clearInterval(shimmerTimer);
98
+ shimmerTimer = null;
99
+ }
100
+ if (phraseTimer) {
101
+ clearInterval(phraseTimer);
102
+ phraseTimer = null;
103
+ }
104
+ loader.stop();
105
+ },
106
+ };
107
+ }
108
+ //# sourceMappingURL=thinking-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking-loader.js","sourceRoot":"","sources":["../../src/tui/thinking-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type Component } from '@earendil-works/pi-tui';
2
+ /** 用户消息:绿色 > 前缀 + 灰底行背景 */
3
+ export declare class UserMessage implements Component {
4
+ private readonly text;
5
+ constructor(content: string);
6
+ invalidate(): void;
7
+ render(width: number): string[];
8
+ }
9
+ /** 流式 AI 回复前缀 */
10
+ export declare function formatAssistantStream(text: string): string;
11
+ /** 静态 AI 回复前缀(非流式 rebuild 用) */
12
+ export declare function formatAssistantMessage(text: string): string;
@@ -0,0 +1,35 @@
1
+ import chalk from 'chalk';
2
+ import { Text } from '@earendil-works/pi-tui';
3
+ function formatUserDisplay(content) {
4
+ const lines = content.split('\n');
5
+ return lines
6
+ .map((line, i) => {
7
+ const prefix = i === 0 ? chalk.green.bold('> ') : ' ';
8
+ return prefix + line;
9
+ })
10
+ .join('\n');
11
+ }
12
+ /** 用户消息:绿色 > 前缀 + 灰底行背景 */
13
+ export class UserMessage {
14
+ text;
15
+ constructor(content) {
16
+ this.text = new Text(formatUserDisplay(content), 1, 0, (t) => chalk.bgGray(t));
17
+ }
18
+ invalidate() {
19
+ this.text.invalidate();
20
+ }
21
+ render(width) {
22
+ return this.text.render(width);
23
+ }
24
+ }
25
+ /** 流式 AI 回复前缀 */
26
+ export function formatAssistantStream(text) {
27
+ if (!text)
28
+ return '● ';
29
+ return `● ${text}`;
30
+ }
31
+ /** 静态 AI 回复前缀(非流式 rebuild 用) */
32
+ export function formatAssistantMessage(text) {
33
+ return text.startsWith('●') ? text : `● ${text}`;
34
+ }
35
+ //# sourceMappingURL=user-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-message.js","sourceRoot":"","sources":["../../src/tui/user-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,IAAI,EAAkB,MAAM,wBAAwB,CAAC;AAE9D,SAAS,iBAAiB,CAAC,OAAe;IACxC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACf,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACxD,OAAO,MAAM,GAAG,IAAI,CAAC;IACvB,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,2BAA2B;AAC3B,MAAM,OAAO,WAAW;IACL,IAAI,CAAO;IAE5B,YAAY,OAAe;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;CACF;AAED,iBAAiB;AACjB,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,OAAO,KAAK,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;AACnD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "hcent",
3
+ "version": "0.1.0",
4
+ "description": "hcent — 终端编码助手,自然语言驱动的终端编程工具",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "engines": {
9
+ "node": ">=20"
10
+ },
11
+ "type": "module",
12
+ "bin": {
13
+ "hcent": "./dist/bin.js"
14
+ },
15
+ "scripts": {
16
+ "dev": "node --env-file=.env --import tsx src/bin.ts",
17
+ "prepare": "node scripts/prepare.mjs",
18
+ "prepack": "npm run build",
19
+ "build": "tsc",
20
+ "lint": "eslint .",
21
+ "lint:fix": "eslint . --fix",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest"
24
+ },
25
+ "simple-git-hooks": {
26
+ "pre-commit": "pnpm exec lint-staged"
27
+ },
28
+ "lint-staged": {
29
+ "*.{ts,mts,cts}": "eslint --fix --max-warnings=0"
30
+ },
31
+ "keywords": [
32
+ "tui",
33
+ "agent",
34
+ "llm",
35
+ "cli",
36
+ "hcent"
37
+ ],
38
+ "license": "MIT",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/HanChen-cn/hcent.git"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/HanChen-cn/hcent/issues"
45
+ },
46
+ "homepage": "https://github.com/HanChen-cn/hcent#readme",
47
+ "packageManager": "pnpm@10.27.0",
48
+ "dependencies": {
49
+ "@earendil-works/pi-tui": "^0.79.3",
50
+ "chalk": "^5.6.2",
51
+ "openai": "^6.43.0"
52
+ },
53
+ "pnpm": {
54
+ "onlyBuiltDependencies": [
55
+ "esbuild"
56
+ ],
57
+ "overrides": {
58
+ "esbuild": "0.28.1"
59
+ }
60
+ },
61
+ "devDependencies": {
62
+ "@eslint/js": "^10.0.1",
63
+ "@rollup/rollup-win32-x64-msvc": "^4.61.1",
64
+ "@types/node": "^26.0.1",
65
+ "eslint": "^10.6.0",
66
+ "eslint-import-resolver-typescript": "^4.4.5",
67
+ "eslint-plugin-import-x": "^4.17.1",
68
+ "lint-staged": "^17.0.8",
69
+ "simple-git-hooks": "^2.13.1",
70
+ "tsx": "^4.22.4",
71
+ "typescript": "^6.0.3",
72
+ "typescript-eslint": "^8.63.0",
73
+ "vitest": "^3.2.6"
74
+ }
75
+ }