agentsx 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 (86) hide show
  1. package/AGENTS.md +49 -0
  2. package/AGENT_PATHS.md +55 -0
  3. package/README.md +32 -0
  4. package/REQUIREMENTS.md +133 -0
  5. package/dist/agents/claude.d.ts +2 -0
  6. package/dist/agents/claude.js +120 -0
  7. package/dist/agents/claude.js.map +1 -0
  8. package/dist/agents/codex.d.ts +2 -0
  9. package/dist/agents/codex.js +68 -0
  10. package/dist/agents/codex.js.map +1 -0
  11. package/dist/agents/copilot.d.ts +2 -0
  12. package/dist/agents/copilot.js +85 -0
  13. package/dist/agents/copilot.js.map +1 -0
  14. package/dist/agents/cursor.d.ts +2 -0
  15. package/dist/agents/cursor.js +84 -0
  16. package/dist/agents/cursor.js.map +1 -0
  17. package/dist/agents/opencode.d.ts +2 -0
  18. package/dist/agents/opencode.js +90 -0
  19. package/dist/agents/opencode.js.map +1 -0
  20. package/dist/agents/registry.d.ts +4 -0
  21. package/dist/agents/registry.js +35 -0
  22. package/dist/agents/registry.js.map +1 -0
  23. package/dist/commands/init.d.ts +1 -0
  24. package/dist/commands/init.js +15 -0
  25. package/dist/commands/init.js.map +1 -0
  26. package/dist/commands/pull.d.ts +2 -0
  27. package/dist/commands/pull.js +5 -0
  28. package/dist/commands/pull.js.map +1 -0
  29. package/dist/commands/push.d.ts +2 -0
  30. package/dist/commands/push.js +5 -0
  31. package/dist/commands/push.js.map +1 -0
  32. package/dist/commands/sync.d.ts +2 -0
  33. package/dist/commands/sync.js +5 -0
  34. package/dist/commands/sync.js.map +1 -0
  35. package/dist/commands/targets.d.ts +1 -0
  36. package/dist/commands/targets.js +17 -0
  37. package/dist/commands/targets.js.map +1 -0
  38. package/dist/core/git.d.ts +6 -0
  39. package/dist/core/git.js +45 -0
  40. package/dist/core/git.js.map +1 -0
  41. package/dist/core/layout.d.ts +3 -0
  42. package/dist/core/layout.js +9 -0
  43. package/dist/core/layout.js.map +1 -0
  44. package/dist/core/planner.d.ts +3 -0
  45. package/dist/core/planner.js +173 -0
  46. package/dist/core/planner.js.map +1 -0
  47. package/dist/core/remote.d.ts +9 -0
  48. package/dist/core/remote.js +28 -0
  49. package/dist/core/remote.js.map +1 -0
  50. package/dist/core/run-sync-command.d.ts +2 -0
  51. package/dist/core/run-sync-command.js +53 -0
  52. package/dist/core/run-sync-command.js.map +1 -0
  53. package/dist/core/scanner.d.ts +4 -0
  54. package/dist/core/scanner.js +58 -0
  55. package/dist/core/scanner.js.map +1 -0
  56. package/dist/core/state.d.ts +10 -0
  57. package/dist/core/state.js +64 -0
  58. package/dist/core/state.js.map +1 -0
  59. package/dist/core/sync-engine.d.ts +21 -0
  60. package/dist/core/sync-engine.js +133 -0
  61. package/dist/core/sync-engine.js.map +1 -0
  62. package/dist/core/targets.d.ts +6 -0
  63. package/dist/core/targets.js +28 -0
  64. package/dist/core/targets.js.map +1 -0
  65. package/dist/index.d.ts +2 -0
  66. package/dist/index.js +86 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/types.d.ts +79 -0
  69. package/dist/types.js +2 -0
  70. package/dist/types.js.map +1 -0
  71. package/dist/ui/prompts.d.ts +4 -0
  72. package/dist/ui/prompts.js +56 -0
  73. package/dist/ui/prompts.js.map +1 -0
  74. package/dist/utils/fs.d.ts +14 -0
  75. package/dist/utils/fs.js +63 -0
  76. package/dist/utils/fs.js.map +1 -0
  77. package/dist/utils/hash.d.ts +1 -0
  78. package/dist/utils/hash.js +7 -0
  79. package/dist/utils/hash.js.map +1 -0
  80. package/dist/utils/path.d.ts +5 -0
  81. package/dist/utils/path.js +46 -0
  82. package/dist/utils/path.js.map +1 -0
  83. package/dist/utils/shell.d.ts +7 -0
  84. package/dist/utils/shell.js +32 -0
  85. package/dist/utils/shell.js.map +1 -0
  86. package/package.json +45 -0
@@ -0,0 +1,63 @@
1
+ import path from "node:path";
2
+ import { mkdir, readdir, rm, stat, copyFile } from "node:fs/promises";
3
+ export async function exists(absPath) {
4
+ try {
5
+ await stat(absPath);
6
+ return true;
7
+ }
8
+ catch {
9
+ return false;
10
+ }
11
+ }
12
+ export async function statFile(absPath) {
13
+ try {
14
+ const fileStat = await stat(absPath);
15
+ if (!fileStat.isFile()) {
16
+ return undefined;
17
+ }
18
+ return { mtimeMs: fileStat.mtimeMs };
19
+ }
20
+ catch {
21
+ return undefined;
22
+ }
23
+ }
24
+ export async function ensureDir(absPath) {
25
+ await mkdir(absPath, { recursive: true });
26
+ }
27
+ export async function listFilesRecursive(basePath) {
28
+ const files = [];
29
+ async function walk(current) {
30
+ const entries = await readdir(current, { withFileTypes: true });
31
+ for (const entry of entries) {
32
+ const fullPath = path.join(current, entry.name);
33
+ if (entry.isDirectory()) {
34
+ await walk(fullPath);
35
+ }
36
+ else if (entry.isFile()) {
37
+ const fileStat = await stat(fullPath);
38
+ files.push({
39
+ absPath: fullPath,
40
+ relPath: path.relative(basePath, fullPath),
41
+ mtimeMs: fileStat.mtimeMs,
42
+ });
43
+ }
44
+ }
45
+ }
46
+ await walk(basePath);
47
+ return files;
48
+ }
49
+ export async function resetDirectoryContents(basePath) {
50
+ const has = await exists(basePath);
51
+ if (!has) {
52
+ return;
53
+ }
54
+ const entries = await readdir(basePath);
55
+ for (const entry of entries) {
56
+ await rm(path.join(basePath, entry), { recursive: true, force: true });
57
+ }
58
+ }
59
+ export async function copySingleFile(src, dest) {
60
+ await ensureDir(path.dirname(dest));
61
+ await copyFile(src, dest);
62
+ }
63
+ //# sourceMappingURL=fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAYtE,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAAe;IAC1C,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAe;IAC5C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAe;IAC7C,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IACvD,MAAM,KAAK,GAAiB,EAAE,CAAC;IAE/B,KAAK,UAAU,IAAI,CAAC,OAAe;QACjC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC1B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACtC,KAAK,CAAC,IAAI,CAAC;oBACT,OAAO,EAAE,QAAQ;oBACjB,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;oBAC1C,OAAO,EAAE,QAAQ,CAAC,OAAO;iBAC1B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,QAAgB;IAC3D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAW,EAAE,IAAY;IAC5D,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACpC,MAAM,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function hashFile(absPath: string): Promise<string>;
@@ -0,0 +1,7 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFile } from "node:fs/promises";
3
+ export async function hashFile(absPath) {
4
+ const data = await readFile(absPath);
5
+ return createHash("sha256").update(data).digest("hex");
6
+ }
7
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAe;IAC5C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { TargetSpec } from "../types.js";
2
+ export declare function expandHome(input: string): string;
3
+ export declare function resolveTargetAbsolutePath(target: TargetSpec, cwd: string): string;
4
+ export declare function ensureUnixSlashes(input: string): string;
5
+ export declare function repoSlugFromUrl(repoUrl: string): string;
@@ -0,0 +1,46 @@
1
+ import { homedir } from "node:os";
2
+ import path from "node:path";
3
+ export function expandHome(input) {
4
+ if (input === "~") {
5
+ return homedir();
6
+ }
7
+ if (input.startsWith("~/")) {
8
+ return path.join(homedir(), input.slice(2));
9
+ }
10
+ return input;
11
+ }
12
+ function pickPlatformPath(platformPath) {
13
+ if (typeof platformPath === "string") {
14
+ return platformPath;
15
+ }
16
+ const selected = platformPath[process.platform] ??
17
+ platformPath.default ??
18
+ platformPath.linux ??
19
+ platformPath.darwin;
20
+ if (!selected) {
21
+ throw new Error(`현재 플랫폼(${process.platform})에 대한 경로가 정의되지 않았습니다.`);
22
+ }
23
+ return selected;
24
+ }
25
+ export function resolveTargetAbsolutePath(target, cwd) {
26
+ const rawPath = pickPlatformPath(target.path);
27
+ if (target.scope === "home") {
28
+ return path.join(homedir(), rawPath);
29
+ }
30
+ return path.join(cwd, rawPath);
31
+ }
32
+ export function ensureUnixSlashes(input) {
33
+ return input.split(path.sep).join("/");
34
+ }
35
+ export function repoSlugFromUrl(repoUrl) {
36
+ const normalized = repoUrl
37
+ .trim()
38
+ .replace(/^https?:\/\//, "")
39
+ .replace(/^git@/, "")
40
+ .replace(/:/g, "/")
41
+ .replace(/\.git$/, "")
42
+ .replace(/[^a-zA-Z0-9/._-]/g, "-")
43
+ .replace(/\/{2,}/g, "/");
44
+ return normalized.replace(/\//g, "__");
45
+ }
46
+ //# sourceMappingURL=path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;QAClB,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,gBAAgB,CAAC,YAA0B;IAClD,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;QACrC,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,MAAM,QAAQ,GACZ,YAAY,CAAC,OAAO,CAAC,QAAwC,CAAC;QAC9D,YAAY,CAAC,OAAO;QACpB,YAAY,CAAC,KAAK;QAClB,YAAY,CAAC,MAAM,CAAC;IAEtB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,UAAU,OAAO,CAAC,QAAQ,uBAAuB,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,MAAkB,EAAE,GAAW;IACvE,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE9C,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,UAAU,GAAG,OAAO;SACvB,IAAI,EAAE;SACN,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;SAC3B,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;SAClB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC;SACjC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAE3B,OAAO,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface ExecResult {
2
+ stdout: string;
3
+ stderr: string;
4
+ status: number;
5
+ }
6
+ export declare function runOrThrow(command: string, args: string[], cwd?: string): ExecResult;
7
+ export declare function run(command: string, args: string[], cwd?: string): ExecResult;
@@ -0,0 +1,32 @@
1
+ import { spawnSync } from "node:child_process";
2
+ export function runOrThrow(command, args, cwd) {
3
+ const result = spawnSync(command, args, {
4
+ cwd,
5
+ encoding: "utf8",
6
+ stdio: ["ignore", "pipe", "pipe"],
7
+ });
8
+ const stdout = result.stdout ?? "";
9
+ const stderr = result.stderr ?? "";
10
+ const status = result.status ?? 1;
11
+ if (status !== 0) {
12
+ const argText = args.join(" ");
13
+ throw new Error([
14
+ `명령 실행 실패: ${command} ${argText}`,
15
+ stderr.trim() || stdout.trim() || "원인을 확인할 수 없습니다."
16
+ ].join("\n"));
17
+ }
18
+ return { stdout, stderr, status };
19
+ }
20
+ export function run(command, args, cwd) {
21
+ const result = spawnSync(command, args, {
22
+ cwd,
23
+ encoding: "utf8",
24
+ stdio: ["ignore", "pipe", "pipe"],
25
+ });
26
+ return {
27
+ stdout: result.stdout ?? "",
28
+ stderr: result.stderr ?? "",
29
+ status: result.status ?? 1,
30
+ };
31
+ }
32
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAQ/C,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,IAAc,EAAE,GAAY;IACtE,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE;QACtC,GAAG;QACH,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;KAClC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IAElC,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC;YACd,aAAa,OAAO,IAAI,OAAO,EAAE;YACjC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,iBAAiB;SACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,IAAc,EAAE,GAAY;IAC/D,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE;QACtC,GAAG;QACH,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;KAClC,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC;KAC3B,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "agentsx",
3
+ "version": "0.1.0",
4
+ "description": "Cross-machine agent config sync CLI",
5
+ "type": "module",
6
+ "files": [
7
+ "dist",
8
+ "README.md",
9
+ "REQUIREMENTS.md",
10
+ "AGENTS.md",
11
+ "AGENT_PATHS.md"
12
+ ],
13
+ "bin": {
14
+ "agentsx": "dist/index.js"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.build.json",
21
+ "dev": "tsx src/index.ts",
22
+ "typecheck": "tsc --noEmit",
23
+ "lint": "eslint .",
24
+ "test": "vitest run",
25
+ "check": "pnpm typecheck && pnpm lint && pnpm test",
26
+ "prepublishOnly": "pnpm check && pnpm build"
27
+ },
28
+ "engines": {
29
+ "node": ">=20.10.0"
30
+ },
31
+ "dependencies": {
32
+ "@inquirer/prompts": "^7.9.0",
33
+ "@optique/core": "^0.9.2",
34
+ "@optique/run": "^0.9.2"
35
+ },
36
+ "devDependencies": {
37
+ "@eslint/js": "^9.23.0",
38
+ "@types/node": "^24.3.0",
39
+ "eslint": "^9.35.0",
40
+ "tsx": "^4.20.5",
41
+ "typescript": "^5.9.2",
42
+ "typescript-eslint": "^8.43.0",
43
+ "vitest": "^3.2.4"
44
+ }
45
+ }