@jaybeeuu/agent-uplink 1.0.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.
@@ -0,0 +1,35 @@
1
+ import { Command } from "commander";
2
+ import { getCapabilitiesDir } from "../config.js";
3
+ import { createLogger } from "../logger.js";
4
+
5
+ const log = createLogger("mcp");
6
+
7
+ export function makeMcpCommand(): Command {
8
+ const cmd = new Command("mcp");
9
+ cmd.description("Manage the MCP (Model Context Protocol) server");
10
+
11
+ cmd
12
+ .command("start")
13
+ .description("Start the MCP server")
14
+ .option("--stdio", "Use stdio transport (default, for use with AI tools)")
15
+ .option("--capabilities-dir <path>", "Override capabilities directory")
16
+ .action(async (opts: { stdio?: boolean; capabilitiesDir?: string }) => {
17
+ const capabilitiesDir = opts.capabilitiesDir ?? getCapabilitiesDir();
18
+
19
+ // Diagnostic output goes to stderr so stdout stays clean for MCP protocol
20
+ log.debug("Starting MCP server (stdio)");
21
+ log.debug(`Capabilities dir: ${capabilitiesDir}`);
22
+
23
+ try {
24
+ const { startStdioServer } = await import("../mcp.js");
25
+ await startStdioServer(capabilitiesDir);
26
+ } catch (err) {
27
+ process.stderr.write(
28
+ `[agent-uplink] MCP server error: ${err instanceof Error ? err.message : String(err)}\n`
29
+ );
30
+ process.exit(1);
31
+ }
32
+ });
33
+
34
+ return cmd;
35
+ }
@@ -0,0 +1,49 @@
1
+ import { Command } from "commander";
2
+ import { syncCapabilities, getGitStatus } from "../git.js";
3
+ import { getCapabilitiesDir, getConfigValue } from "../config.js";
4
+ import { createLogger } from "../logger.js";
5
+
6
+ const log = createLogger("sync");
7
+
8
+ export function makeSyncCommand(): Command {
9
+ const cmd = new Command("sync");
10
+ cmd
11
+ .description(
12
+ "Commit and push all capability changes to the configured git remote"
13
+ )
14
+ .option("--dry-run", "Show what would be synced without making changes")
15
+ .action(async (opts: { dryRun?: boolean }) => {
16
+ const capabilitiesDir = getCapabilitiesDir();
17
+
18
+ if (opts.dryRun) {
19
+ const status = await getGitStatus(capabilitiesDir);
20
+ if (status.clean) {
21
+ log.warn("Nothing to sync.");
22
+ } else {
23
+ log.info("Files that would be committed:");
24
+ for (const f of status.files) {
25
+ log.dim(f);
26
+ }
27
+ }
28
+ return;
29
+ }
30
+
31
+ try {
32
+ log.debug(`Syncing ${capabilitiesDir}...`);
33
+ const result = await syncCapabilities(capabilitiesDir, getConfigValue("gitRemote"));
34
+
35
+ if (!result.committed) {
36
+ log.warn(result.message);
37
+ } else if (result.pushed) {
38
+ log.success(result.message);
39
+ } else {
40
+ log.warn(result.message);
41
+ }
42
+ } catch (err) {
43
+ log.error(err);
44
+ process.exit(1);
45
+ }
46
+ });
47
+
48
+ return cmd;
49
+ }
@@ -0,0 +1,84 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdirSync, rmSync } from "fs";
3
+ import { join } from "path";
4
+ import { tmpdir } from "os";
5
+ import {
6
+ getConfigValue,
7
+ setConfigValue,
8
+ getConfigEntries,
9
+ } from "./config.js";
10
+
11
+ const TMP = join(tmpdir(), `uplink-config-test-${String(process.pid)}`);
12
+
13
+ beforeEach(() => {
14
+ mkdirSync(TMP, { recursive: true });
15
+ // Override home directory for each test
16
+ process.env["HOME"] = TMP;
17
+ });
18
+
19
+ afterEach(() => {
20
+ rmSync(TMP, { recursive: true, force: true });
21
+ delete process.env["HOME"];
22
+ });
23
+
24
+ describe("getConfigValue", () => {
25
+ it("returns default capabilitiesDir when no config file exists", () => {
26
+ const dir = getConfigValue("capabilitiesDir");
27
+ expect(dir).toContain(".agent-uplink");
28
+ expect(dir).toContain("capabilities");
29
+ });
30
+
31
+ it("returns stored value after setConfigValue", () => {
32
+ setConfigValue("editor", "vim");
33
+ expect(getConfigValue("editor")).toBe("vim");
34
+ });
35
+ });
36
+
37
+ describe("setConfigValue", () => {
38
+ it("sets and gets individual config values", () => {
39
+ setConfigValue("editor", "nano");
40
+ expect(getConfigValue("editor")).toBe("nano");
41
+ });
42
+
43
+ it("leaves other values intact when setting one key", () => {
44
+ setConfigValue("capabilitiesDir", "/original");
45
+ setConfigValue("editor", "vim");
46
+ setConfigValue("editor", "emacs");
47
+ expect(getConfigValue("capabilitiesDir")).toBe("/original");
48
+ expect(getConfigValue("editor")).toBe("emacs");
49
+ });
50
+
51
+ it("persists multiple keys in round-trip", () => {
52
+ setConfigValue("capabilitiesDir", "/some/dir");
53
+ setConfigValue("editor", "code");
54
+ setConfigValue("gitRemote", "upstream");
55
+ expect(getConfigValue("capabilitiesDir")).toBe("/some/dir");
56
+ expect(getConfigValue("editor")).toBe("code");
57
+ expect(getConfigValue("gitRemote")).toBe("upstream");
58
+ });
59
+ });
60
+
61
+ describe("getConfigEntries", () => {
62
+ it("returns all config keys with their values and defaults", () => {
63
+ const entries = getConfigEntries();
64
+ const keys = entries.map((e) => e.key);
65
+ expect(keys).toContain("capabilitiesDir");
66
+ });
67
+
68
+ it("value is undefined for unset optional keys", () => {
69
+ const entry = getConfigEntries().find((e) => e.key === "editor");
70
+ expect(entry?.value).toBeUndefined();
71
+ });
72
+
73
+ it("value is set when key has been configured", () => {
74
+ setConfigValue("editor", "vim");
75
+ const entry = getConfigEntries().find((e) => e.key === "editor");
76
+ expect(entry?.value).toBe("vim");
77
+ });
78
+
79
+ it("defaultValue is set for keys that have defaults", () => {
80
+ const entry = getConfigEntries().find((e) => e.key === "capabilitiesDir");
81
+ expect(entry?.defaultValue).toBeDefined();
82
+ expect(entry?.defaultValue).toContain("capabilities");
83
+ });
84
+ });
package/src/config.ts ADDED
@@ -0,0 +1,113 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
2
+ import { join, dirname } from "path";
3
+ import { homedir } from "os";
4
+ import { createLogger } from "./logger.js";
5
+ import { ConfigSchema } from "./types.js";
6
+ import type { Config } from "./types.js";
7
+
8
+ const log = createLogger("config");
9
+
10
+ function getConfigDir_(): string {
11
+ return join(homedir(), ".agent-uplink");
12
+ }
13
+
14
+ function getConfigFile(): string {
15
+ return join(getConfigDir_(), "config.json");
16
+ }
17
+
18
+ function getDefaults(): Config {
19
+ return {
20
+ capabilitiesDir: join(getConfigDir_(), "capabilities"),
21
+ };
22
+ }
23
+
24
+ export function getConfigDir(): string {
25
+ return getConfigDir_();
26
+ }
27
+
28
+ export function getConfigFilePath(): string {
29
+ return getConfigFile();
30
+ }
31
+
32
+ function loadRawConfig(): Partial<Config> {
33
+ const configFile = getConfigFile();
34
+ if (!existsSync(configFile)) {
35
+ return {};
36
+ }
37
+ try {
38
+ const raw = readFileSync(configFile, "utf-8");
39
+ const parsed: unknown = JSON.parse(raw);
40
+ const result = ConfigSchema.partial().safeParse(parsed);
41
+ if (!result.success) {
42
+ log.warn(
43
+ `Config file at ${configFile} is invalid: ${result.error.message}. Using defaults.`
44
+ );
45
+ return {};
46
+ }
47
+ return result.data;
48
+ } catch (err) {
49
+ log.warn(
50
+ `Could not read config file at ${configFile}: ${err instanceof Error ? err.message : String(err)}. Using defaults.`
51
+ );
52
+ return {};
53
+ }
54
+ }
55
+
56
+ function loadConfig(): Config {
57
+ return { ...getDefaults(), ...loadRawConfig() };
58
+ }
59
+
60
+ function saveConfig(config: Config): void {
61
+ const configFile = getConfigFile();
62
+ const dir = dirname(configFile);
63
+ if (!existsSync(dir)) {
64
+ mkdirSync(dir, { recursive: true });
65
+ }
66
+ writeFileSync(configFile, JSON.stringify(config, null, 2) + "\n", "utf-8");
67
+ }
68
+
69
+ export function getConfigValue<K extends keyof Config>(key: K): Config[K] {
70
+ return loadConfig()[key];
71
+ }
72
+
73
+ export function setConfigValue<K extends keyof Config>(
74
+ key: K,
75
+ value: Config[K]
76
+ ): void {
77
+ const config = loadConfig();
78
+ config[key] = value;
79
+ saveConfig(config);
80
+ }
81
+
82
+ export type ConfigEntry = {
83
+ key: keyof Config;
84
+ value: Config[keyof Config] | undefined;
85
+ defaultValue: Config[keyof Config] | undefined;
86
+ };
87
+
88
+ export function getConfigEntries(): ConfigEntry[] {
89
+ const raw = loadRawConfig();
90
+ const defaults = getDefaults();
91
+ const keys = new Set([
92
+ ...(Object.keys(defaults) as (keyof Config)[]),
93
+ ...(Object.keys(raw) as (keyof Config)[]),
94
+ ]);
95
+ return [...keys].map((key) => ({
96
+ key,
97
+ value: raw[key],
98
+ defaultValue: defaults[key],
99
+ }));
100
+ }
101
+
102
+ export function ensureConfigFile(): void {
103
+ saveConfig(loadConfig());
104
+ }
105
+
106
+ export function getCapabilitiesDir(): string {
107
+ return loadConfig().capabilitiesDir;
108
+ }
109
+
110
+ export function resetConfig(): void {
111
+ const capabilitiesDir = getConfigValue("capabilitiesDir");
112
+ saveConfig({ capabilitiesDir });
113
+ }
package/src/editor.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { spawn } from "child_process";
2
+ import { existsSync } from "fs";
3
+ import { getConfigValue } from "./config.js";
4
+
5
+ function getDefaultEditor(): string {
6
+ return (
7
+ getConfigValue("editor") ??
8
+ process.env["VISUAL"] ??
9
+ process.env["EDITOR"] ??
10
+ (process.platform === "win32" ? "notepad" : "vi")
11
+ );
12
+ }
13
+
14
+ export async function openInEditor(
15
+ filePath: string,
16
+ editorOverride?: string
17
+ ): Promise<void> {
18
+ if (!existsSync(filePath)) {
19
+ throw new Error(`File not found: ${filePath}`);
20
+ }
21
+
22
+ const editor = editorOverride ?? getDefaultEditor();
23
+ const parts = editor.split(" ");
24
+ const cmd = parts[0];
25
+ const args = [...parts.slice(1), filePath];
26
+
27
+ return new Promise((resolve, reject) => {
28
+ const child = spawn(cmd, args, {
29
+ stdio: "inherit",
30
+ shell: process.platform === "win32",
31
+ });
32
+
33
+ child.on("exit", (code) => {
34
+ if (code === 0 || code === null) {
35
+ resolve();
36
+ } else {
37
+ reject(new Error(`Editor exited with code ${code}`));
38
+ }
39
+ });
40
+
41
+ child.on("error", (err) => {
42
+ reject(
43
+ new Error(`Failed to launch editor '${editor}': ${err.message}`)
44
+ );
45
+ });
46
+ });
47
+ }
package/src/git.ts ADDED
@@ -0,0 +1,84 @@
1
+ import { simpleGit } from "simple-git";
2
+ import type { SimpleGit } from "simple-git";
3
+ import { existsSync } from "fs";
4
+ import type { SyncResult } from "./types.js";
5
+
6
+ export function getGit(dir: string): SimpleGit {
7
+ return simpleGit(dir);
8
+ }
9
+
10
+ async function isGitRepo(dir: string): Promise<boolean> {
11
+ if (!existsSync(dir)) return false;
12
+ try {
13
+ const git = getGit(dir);
14
+ await git.status();
15
+ return true;
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
20
+
21
+ export async function syncCapabilities(
22
+ dir: string,
23
+ remote?: string
24
+ ): Promise<SyncResult> {
25
+ const git = getGit(dir);
26
+
27
+ const isRepo = await isGitRepo(dir);
28
+ if (!isRepo) {
29
+ throw new Error(
30
+ `'${dir}' is not a git repository. Run 'git init' there first, or use 'uplink config set capabilitiesDir <path>' to point to an existing git repo.`
31
+ );
32
+ }
33
+
34
+ const status = await git.status();
35
+ if (status.files.length === 0) {
36
+ return { committed: false, pushed: false, message: "Nothing to sync." };
37
+ }
38
+
39
+ const changed = status.files.map((f) => f.path).join(", ");
40
+ const now = new Date().toISOString().slice(0, 10);
41
+ const commitMessage = `chore: sync capabilities on ${now} (${status.files.length} file(s): ${changed})`;
42
+
43
+ await git.add(".");
44
+ await git.commit(commitMessage);
45
+
46
+ const effectiveRemote = remote ?? "origin";
47
+ let pushed = false;
48
+
49
+ try {
50
+ const remotes = await git.getRemotes();
51
+ const hasRemote = remotes.some((r) => r.name === effectiveRemote);
52
+ if (hasRemote) {
53
+ const branch = (await git.branchLocal()).current;
54
+ await git.push(effectiveRemote, branch, ["--set-upstream"]);
55
+ pushed = true;
56
+ }
57
+ } catch (err) {
58
+ const msg = err instanceof Error ? err.message : String(err);
59
+ return {
60
+ committed: true,
61
+ pushed: false,
62
+ message: `Committed but push failed: ${msg}`,
63
+ };
64
+ }
65
+
66
+ return {
67
+ committed: true,
68
+ pushed,
69
+ message: pushed
70
+ ? `Synced: ${commitMessage}`
71
+ : `Committed locally (no remote configured): ${commitMessage}`,
72
+ };
73
+ }
74
+
75
+ export async function getGitStatus(
76
+ dir: string
77
+ ): Promise<{ clean: boolean; files: string[] }> {
78
+ const git = getGit(dir);
79
+ const status = await git.status();
80
+ return {
81
+ clean: status.files.length === 0,
82
+ files: status.files.map((f) => `${f.index}${f.working_dir} ${f.path}`),
83
+ };
84
+ }
package/src/logger.ts ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Centralised logging for agent-uplink.
3
+ *
4
+ * Debug output is gated behind the DEBUG environment variable using the
5
+ * standard `debug` package convention, e.g.:
6
+ * DEBUG=agent-uplink:* – enable all modules
7
+ * DEBUG=agent-uplink:config – enable config module only
8
+ * DEBUG=agent-uplink:install – enable install module only
9
+ */
10
+ import createDebug from "debug";
11
+ import chalk from "chalk";
12
+
13
+ export function toErrorMessage(err: unknown): string {
14
+ if (err instanceof Error) return err.message;
15
+ if (typeof err === "string") return err;
16
+ return String(err);
17
+ }
18
+
19
+ export type Logger = {
20
+ debug: (...args: unknown[]) => void;
21
+ info: (...args: unknown[]) => void;
22
+ warn: (...args: unknown[]) => void;
23
+ error: (err: unknown, ...extra: unknown[]) => void;
24
+ success: (...args: unknown[]) => void;
25
+ dim: (...args: unknown[]) => void;
26
+ };
27
+
28
+ export function createLogger(namespace: string): Logger {
29
+ const debugLog = createDebug(`agent-uplink:${namespace}`);
30
+
31
+ return {
32
+ debug(...args) {
33
+ debugLog(args.map(String).join(" "));
34
+ },
35
+
36
+ info(...args) {
37
+ console.log(args.map(String).join(" "));
38
+ },
39
+
40
+ warn(...args) {
41
+ console.warn(chalk.yellow(`⚠ ${args.map(String).join(" ")}`));
42
+ },
43
+
44
+ error(err, ...extra) {
45
+ const msg = [toErrorMessage(err), ...extra.map(String)].join(" ");
46
+ console.error(chalk.red(`✗ ${msg}`));
47
+ },
48
+
49
+ success(...args) {
50
+ console.log(chalk.green(`✓ ${args.map(String).join(" ")}`));
51
+ },
52
+
53
+ dim(...args) {
54
+ console.log(chalk.dim(` ${args.map(String).join(" ")}`));
55
+ },
56
+ };
57
+ }
58
+
59
+ /** Shared root logger for the CLI entry point. */
60
+ export const rootLogger = createLogger("cli");
package/src/mcp.ts ADDED
@@ -0,0 +1,156 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { z } from "zod";
4
+ import {
5
+ createCapability,
6
+ readCapability,
7
+ updateCapability,
8
+ deleteCapability,
9
+ listCapabilities,
10
+ } from "./capabilities.js";
11
+ import { syncCapabilities } from "./git.js";
12
+ import { getConfigValue } from "./config.js";
13
+ import { CapabilityTypeSchema } from "./types.js";
14
+
15
+ type McpToolResult = { content: { type: "text"; text: string }[]; isError?: boolean };
16
+
17
+ function mcpSuccess(text: string): McpToolResult {
18
+ return { content: [{ type: "text", text }] };
19
+ }
20
+
21
+ function mcpError(err: unknown): McpToolResult {
22
+ const msg = err instanceof Error ? err.message : String(err);
23
+ return { content: [{ type: "text", text: `Error: ${msg}` }], isError: true };
24
+ }
25
+
26
+ export function createMcpServer(capabilitiesDir: string): McpServer {
27
+ const server = new McpServer({
28
+ name: "agent-uplink",
29
+ version: "1.0.0",
30
+ });
31
+
32
+ server.registerTool(
33
+ "list_capabilities",
34
+ {
35
+ description: "List all capabilities of a given type (skill, agent, instruction)",
36
+ inputSchema: {
37
+ type: CapabilityTypeSchema.describe(
38
+ "Type of capability: skill, agent, or instruction"
39
+ ),
40
+ },
41
+ },
42
+ ({ type }) => {
43
+ const items = listCapabilities(capabilitiesDir, type);
44
+ return mcpSuccess(
45
+ items.length > 0
46
+ ? `${type}s:\n${items.map((i) => `- ${i}`).join("\n")}`
47
+ : `No ${type}s found.`
48
+ );
49
+ }
50
+ );
51
+
52
+ server.registerTool(
53
+ "get_capability",
54
+ {
55
+ description: "Get the content of a specific capability",
56
+ inputSchema: {
57
+ type: CapabilityTypeSchema.describe("Type of capability"),
58
+ name: z.string().describe("Name of the capability"),
59
+ },
60
+ },
61
+ ({ type, name }) => {
62
+ try {
63
+ const cap = readCapability(capabilitiesDir, type, name);
64
+ return mcpSuccess(cap.content);
65
+ } catch (err) {
66
+ return mcpError(err);
67
+ }
68
+ }
69
+ );
70
+
71
+ server.registerTool(
72
+ "create_capability",
73
+ {
74
+ description: "Create a new capability with the given content",
75
+ inputSchema: {
76
+ type: CapabilityTypeSchema.describe("Type of capability to create"),
77
+ name: z.string().describe("Name of the capability"),
78
+ content: z
79
+ .string()
80
+ .optional()
81
+ .describe("Content for the capability (uses template if omitted)"),
82
+ },
83
+ },
84
+ ({ type, name, content }) => {
85
+ try {
86
+ const cap = createCapability(capabilitiesDir, type, name, content);
87
+ return mcpSuccess(`Created ${type} '${name}' at ${cap.path}`);
88
+ } catch (err) {
89
+ return mcpError(err);
90
+ }
91
+ }
92
+ );
93
+
94
+ server.registerTool(
95
+ "update_capability",
96
+ {
97
+ description: "Update the content of an existing capability",
98
+ inputSchema: {
99
+ type: CapabilityTypeSchema.describe("Type of capability"),
100
+ name: z.string().describe("Name of the capability"),
101
+ content: z.string().describe("New content for the capability"),
102
+ },
103
+ },
104
+ ({ type, name, content }) => {
105
+ try {
106
+ const cap = updateCapability(capabilitiesDir, type, name, content);
107
+ return mcpSuccess(`Updated ${type} '${name}' at ${cap.path}`);
108
+ } catch (err) {
109
+ return mcpError(err);
110
+ }
111
+ }
112
+ );
113
+
114
+ server.registerTool(
115
+ "delete_capability",
116
+ {
117
+ description: "Delete a capability",
118
+ inputSchema: {
119
+ type: CapabilityTypeSchema.describe("Type of capability"),
120
+ name: z.string().describe("Name of the capability to delete"),
121
+ },
122
+ },
123
+ ({ type, name }) => {
124
+ try {
125
+ deleteCapability(capabilitiesDir, type, name);
126
+ return mcpSuccess(`Deleted ${type} '${name}'`);
127
+ } catch (err) {
128
+ return mcpError(err);
129
+ }
130
+ }
131
+ );
132
+
133
+ server.registerTool(
134
+ "sync_capabilities",
135
+ {
136
+ description: "Commit and push all capability changes to the configured git remote",
137
+ inputSchema: {},
138
+ },
139
+ async () => {
140
+ try {
141
+ const result = await syncCapabilities(capabilitiesDir, getConfigValue("gitRemote"));
142
+ return mcpSuccess(result.message);
143
+ } catch (err) {
144
+ return mcpError(err);
145
+ }
146
+ }
147
+ );
148
+
149
+ return server;
150
+ }
151
+
152
+ export async function startStdioServer(capabilitiesDir: string): Promise<void> {
153
+ const server = createMcpServer(capabilitiesDir);
154
+ const transport = new StdioServerTransport();
155
+ await server.connect(transport);
156
+ }
package/src/types.ts ADDED
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+
3
+ export const CapabilityTypeSchema = z.enum(["skill", "agent", "instruction"]);
4
+ export type CapabilityType = z.infer<typeof CapabilityTypeSchema>;
5
+
6
+ export const ConfigSchema = z.object({
7
+ capabilitiesDir: z.string(),
8
+ editor: z.string().optional(),
9
+ gitRemote: z.string().optional(),
10
+ });
11
+ export type Config = z.infer<typeof ConfigSchema>;
12
+
13
+ export interface Capability {
14
+ name: string;
15
+ type: CapabilityType;
16
+ path: string;
17
+ content: string;
18
+ }
19
+
20
+ export interface SyncResult {
21
+ committed: boolean;
22
+ pushed: boolean;
23
+ message: string;
24
+ }
25
+
26
+ export type Extension = `.${string}`;
27
+
28
+ export const CAPABILITY_TYPES: CapabilityType[] = ["skill", "agent", "instruction"];
29
+
30
+ export const CAPABILITY_EXTENSIONS: { [K in CapabilityType]: Extension } = {
31
+ skill: ".md",
32
+ agent: ".md",
33
+ instruction: ".md",
34
+ };
35
+
36
+ export const CAPABILITY_DIRS: { [K in CapabilityType]: string } = {
37
+ skill: "skills",
38
+ agent: "agents",
39
+ instruction: "instructions",
40
+ };
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "noEmit": false,
5
+ "outDir": "./dist",
6
+ "rootDir": "./src",
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "sourceMap": true
10
+ },
11
+ "include": ["src/**/*"],
12
+ "exclude": ["node_modules", "dist", "src/**/*.test.ts"]
13
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": ["ES2022"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "noEmit": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true
13
+ },
14
+ "include": ["src/**/*", "vitest.config.ts"]
15
+ }