@xskills/connector 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kyler Zanuck
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # XSkills Connector
2
+
3
+ XSkills Connector installs checksum-approved skill packages into a selected local agent harness on macOS. Pair it once, then approvals from XSkills can be delivered automatically when the Mac is online.
4
+
5
+ ## Requirements
6
+
7
+ - macOS
8
+ - Node.js 22 or newer
9
+ - An XSkills account with Codex, Claude Code, or Cursor selected as its harness
10
+
11
+ ## Install
12
+
13
+ Use the exact version shown by XSkills. For example:
14
+
15
+ ```bash
16
+ npx --yes @xskills/connector@0.1.0 install --harness codex --app https://xskills.app
17
+ ```
18
+
19
+ The command opens a short-lived browser pairing page, stores the device credential in macOS Keychain, and creates a per-user LaunchAgent. Skills are installed under the selected harness root:
20
+
21
+ - Codex: `~/.agents/skills`
22
+ - Claude Code: `~/.claude/skills`
23
+ - Cursor: `~/.cursor/skills`
24
+
25
+ ## Commands
26
+
27
+ ```bash
28
+ xskills status
29
+ xskills update
30
+ xskills disconnect
31
+ ```
32
+
33
+ ## Security model
34
+
35
+ The connector validates every file hash and the aggregate package checksum, rejects path traversal and unmanaged-directory collisions, and installs by atomic directory swap. Packaged scripts are written as text and are never executed by the connector. Device credentials are stored in macOS Keychain and can be revoked from XSkills Settings or with `xskills disconnect`.
36
+
37
+ Source and issue tracking: <https://github.com/kylerzanuck-work/xskillsai>
package/dist/cli.js ADDED
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env node
2
+ import { randomBytes } from "node:crypto";
3
+ import { execFileSync, spawn } from "node:child_process";
4
+ import { chmod, copyFile, mkdir, readFile, rm, writeFile, } from "node:fs/promises";
5
+ import { homedir, hostname, platform, arch as nodeArch } from "node:os";
6
+ import { dirname, join, resolve } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { INSTALL_ROOTS, InstallError, installJob, } from "./installer.js";
9
+ const VERSION = "0.1.0";
10
+ const SERVICE = "ai.xskills.connector";
11
+ const APP_DIR = join(homedir(), "Library", "Application Support", "XSkills");
12
+ const CONFIG_PATH = join(APP_DIR, "config.json");
13
+ const RUNTIME_PATH = join(APP_DIR, "connector.mjs");
14
+ const INSTALLER_RUNTIME_PATH = join(APP_DIR, "installer.js");
15
+ const LOG_PATH = join(homedir(), "Library", "Logs", "XSkills", "connector.log");
16
+ const PLIST_PATH = join(homedir(), "Library", "LaunchAgents", `${SERVICE}.plist`);
17
+ class FatalConnectorError extends Error {
18
+ }
19
+ function sleep(ms) {
20
+ return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
21
+ }
22
+ function option(name) {
23
+ const index = process.argv.indexOf(name);
24
+ return index >= 0 ? process.argv[index + 1] : undefined;
25
+ }
26
+ function requireMac() {
27
+ if (platform() !== "darwin")
28
+ throw new Error("XSkills Connector 0.1 supports macOS only.");
29
+ if (Number(process.versions.node.split(".")[0]) < 22)
30
+ throw new Error("Node.js 22 or newer is required.");
31
+ }
32
+ function parseHarness(value) {
33
+ if (value && value in INSTALL_ROOTS)
34
+ return value;
35
+ throw new Error("Choose --harness codex, claude-code, or cursor.");
36
+ }
37
+ function normalizeAppUrl(value) {
38
+ const url = new URL(value ?? "https://xskills.app");
39
+ if (url.protocol !== "https:" &&
40
+ !["localhost", "127.0.0.1"].includes(url.hostname)) {
41
+ throw new Error("The XSkills app URL must use HTTPS.");
42
+ }
43
+ return url.origin;
44
+ }
45
+ function keychainSecret(deviceId) {
46
+ return execFileSync("/usr/bin/security", ["find-generic-password", "-w", "-s", SERVICE, "-a", deviceId], { encoding: "utf8" }).trim();
47
+ }
48
+ function saveKeychainSecret(deviceId, secret) {
49
+ execFileSync("/usr/bin/security", ["add-generic-password", "-U", "-s", SERVICE, "-a", deviceId, "-w", secret], { stdio: "ignore" });
50
+ }
51
+ function removeKeychainSecret(deviceId) {
52
+ try {
53
+ execFileSync("/usr/bin/security", ["delete-generic-password", "-s", SERVICE, "-a", deviceId], { stdio: "ignore" });
54
+ }
55
+ catch {
56
+ /* Already removed. */
57
+ }
58
+ }
59
+ async function api(appUrl, path, init = {}) {
60
+ return fetch(`${appUrl}${path}`, {
61
+ ...init,
62
+ headers: { "Content-Type": "application/json", ...init.headers },
63
+ signal: AbortSignal.timeout(20_000),
64
+ });
65
+ }
66
+ async function authorizedApi(config, path, init = {}) {
67
+ const secret = keychainSecret(config.deviceId);
68
+ return api(config.appUrl, path, {
69
+ ...init,
70
+ headers: {
71
+ ...init.headers,
72
+ Authorization: `Bearer xsdev_${config.deviceId}.${secret}`,
73
+ },
74
+ });
75
+ }
76
+ async function readConfig() {
77
+ return JSON.parse(await readFile(CONFIG_PATH, "utf8"));
78
+ }
79
+ function xml(value) {
80
+ return value
81
+ .replaceAll("&", "&amp;")
82
+ .replaceAll("<", "&lt;")
83
+ .replaceAll(">", "&gt;")
84
+ .replaceAll('"', "&quot;");
85
+ }
86
+ async function installLaunchAgent() {
87
+ await mkdir(dirname(PLIST_PATH), { recursive: true });
88
+ await mkdir(dirname(LOG_PATH), { recursive: true });
89
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
90
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
91
+ <plist version="1.0"><dict>
92
+ <key>Label</key><string>${SERVICE}</string>
93
+ <key>ProgramArguments</key><array><string>${xml(process.execPath)}</string><string>${xml(RUNTIME_PATH)}</string><string>run</string></array>
94
+ <key>RunAtLoad</key><true/><key>KeepAlive</key><dict><key>NetworkState</key><true/></dict>
95
+ <key>ThrottleInterval</key><integer>10</integer>
96
+ <key>StandardOutPath</key><string>${xml(LOG_PATH)}</string><key>StandardErrorPath</key><string>${xml(LOG_PATH)}</string>
97
+ </dict></plist>\n`;
98
+ await writeFile(PLIST_PATH, plist, { mode: 0o600 });
99
+ const domain = `gui/${process.getuid?.() ?? 0}`;
100
+ try {
101
+ execFileSync("/bin/launchctl", ["bootout", domain, PLIST_PATH], {
102
+ stdio: "ignore",
103
+ });
104
+ }
105
+ catch {
106
+ /* Not loaded yet. */
107
+ }
108
+ execFileSync("/bin/launchctl", ["bootstrap", domain, PLIST_PATH], {
109
+ stdio: "ignore",
110
+ });
111
+ execFileSync("/bin/launchctl", ["kickstart", "-k", `${domain}/${SERVICE}`], {
112
+ stdio: "ignore",
113
+ });
114
+ }
115
+ async function copyRuntime() {
116
+ await mkdir(APP_DIR, { recursive: true, mode: 0o700 });
117
+ const current = fileURLToPath(import.meta.url);
118
+ if (resolve(current) !== resolve(RUNTIME_PATH))
119
+ await copyFile(current, RUNTIME_PATH);
120
+ const installerSource = join(dirname(current), "installer.js");
121
+ if (resolve(installerSource) !== resolve(INSTALLER_RUNTIME_PATH))
122
+ await copyFile(installerSource, INSTALLER_RUNTIME_PATH);
123
+ await chmod(RUNTIME_PATH, 0o700);
124
+ await chmod(INSTALLER_RUNTIME_PATH, 0o600);
125
+ }
126
+ async function pair(harness, appUrl) {
127
+ const deviceSecret = randomBytes(32).toString("base64url");
128
+ const response = await api(appUrl, "/api/connector/device-codes", {
129
+ method: "POST",
130
+ body: JSON.stringify({
131
+ harness,
132
+ platform: "darwin",
133
+ arch: nodeArch() === "arm64" ? "arm64" : "x64",
134
+ deviceName: hostname(),
135
+ connectorVersion: VERSION,
136
+ deviceSecret,
137
+ }),
138
+ });
139
+ const started = (await response.json());
140
+ if (!response.ok || !started.deviceCode || !started.verificationUrl)
141
+ throw new Error(started.error ?? "Could not start pairing.");
142
+ console.log(`Pairing code: ${started.userCode}\nOpen: ${started.verificationUrl}`);
143
+ spawn("/usr/bin/open", [started.verificationUrl], {
144
+ detached: true,
145
+ stdio: "ignore",
146
+ }).unref();
147
+ const expiresAt = new Date(started.expiresAt ?? Date.now() + 600_000).getTime();
148
+ while (Date.now() < expiresAt) {
149
+ await sleep((started.interval ?? 2) * 1000);
150
+ const tokenResponse = await api(appUrl, "/api/connector/token", {
151
+ method: "POST",
152
+ body: JSON.stringify({ deviceCode: started.deviceCode }),
153
+ });
154
+ if (tokenResponse.status === 428)
155
+ continue;
156
+ const token = (await tokenResponse.json());
157
+ if (!tokenResponse.ok || !token.deviceId)
158
+ throw new Error(token.error ?? "Could not finish pairing.");
159
+ saveKeychainSecret(token.deviceId, deviceSecret);
160
+ const config = {
161
+ appUrl,
162
+ deviceId: token.deviceId,
163
+ deviceName: hostname(),
164
+ harness,
165
+ connectorVersion: VERSION,
166
+ };
167
+ await writeFile(CONFIG_PATH, `${JSON.stringify(config, null, 2)}\n`, {
168
+ mode: 0o600,
169
+ });
170
+ return config;
171
+ }
172
+ throw new Error("The pairing code expired. Run the install command again.");
173
+ }
174
+ async function reportFailure(config, job, error) {
175
+ const failure = error instanceof InstallError
176
+ ? error
177
+ : new InstallError(error instanceof Error ? error.message : "Installation failed", true);
178
+ try {
179
+ await authorizedApi(config, `/api/connector/jobs/${job.installationId}/fail`, {
180
+ method: "POST",
181
+ body: JSON.stringify({
182
+ leaseToken: job.leaseToken,
183
+ message: failure.message,
184
+ retryable: failure.retryable,
185
+ }),
186
+ });
187
+ }
188
+ catch {
189
+ /* The lease will expire and make the job claimable again. */
190
+ }
191
+ }
192
+ async function run() {
193
+ requireMac();
194
+ const config = await readConfig();
195
+ let idleDelay = 5000;
196
+ for (;;) {
197
+ try {
198
+ const response = await authorizedApi(config, "/api/connector/jobs/claim", { method: "POST", body: "{}" });
199
+ if (response.status === 204) {
200
+ await sleep(idleDelay);
201
+ idleDelay = Math.min(60_000, idleDelay + 5000);
202
+ continue;
203
+ }
204
+ if (response.status === 401)
205
+ throw new FatalConnectorError("Connector authorization was revoked. Pair this Mac again.");
206
+ if (response.status === 426) {
207
+ const upgrade = (await response.json().catch(() => ({})));
208
+ const requiredVersion = upgrade.requiredVersion ?? "latest";
209
+ throw new FatalConnectorError(`Connector ${VERSION} is out of date. Run: npx --yes @xskills/connector@${requiredVersion} update`);
210
+ }
211
+ if (!response.ok) {
212
+ await sleep(15_000);
213
+ continue;
214
+ }
215
+ idleDelay = 5000;
216
+ const job = (await response.json());
217
+ try {
218
+ const installed = await installJob(job, config);
219
+ await authorizedApi(config, `/api/connector/jobs/${job.installationId}/complete`, {
220
+ method: "POST",
221
+ body: JSON.stringify({
222
+ leaseToken: job.leaseToken,
223
+ status: installed.status,
224
+ packageChecksum: job.package.checksum,
225
+ installedAt: new Date().toISOString(),
226
+ location: installed.location,
227
+ }),
228
+ });
229
+ }
230
+ catch (error) {
231
+ await reportFailure(config, job, error);
232
+ }
233
+ }
234
+ catch (error) {
235
+ console.error(new Date().toISOString(), error instanceof Error ? error.message : error);
236
+ if (error instanceof FatalConnectorError)
237
+ return;
238
+ await sleep(30_000);
239
+ }
240
+ }
241
+ }
242
+ async function install() {
243
+ requireMac();
244
+ const harness = parseHarness(option("--harness"));
245
+ const appUrl = normalizeAppUrl(option("--app"));
246
+ await copyRuntime();
247
+ const config = await pair(harness, appUrl);
248
+ await installLaunchAgent();
249
+ console.log(`${harness} is connected on ${config.deviceName}. Approved skills will install automatically.`);
250
+ }
251
+ async function status() {
252
+ const config = await readConfig();
253
+ const response = await authorizedApi(config, "/api/connector/device");
254
+ console.log(`${config.harness} on ${config.deviceName}: ${response.status === 401 ? "revoked" : "connected"} (connector ${config.connectorVersion})`);
255
+ }
256
+ async function disconnect() {
257
+ const config = await readConfig();
258
+ try {
259
+ await authorizedApi(config, "/api/connector/device", {
260
+ method: "DELETE",
261
+ body: "{}",
262
+ });
263
+ }
264
+ catch {
265
+ /* Continue local cleanup. */
266
+ }
267
+ const domain = `gui/${process.getuid?.() ?? 0}`;
268
+ try {
269
+ execFileSync("/bin/launchctl", ["bootout", domain, PLIST_PATH], {
270
+ stdio: "ignore",
271
+ });
272
+ }
273
+ catch {
274
+ /* Already stopped. */
275
+ }
276
+ removeKeychainSecret(config.deviceId);
277
+ await rm(PLIST_PATH, { force: true });
278
+ await rm(CONFIG_PATH, { force: true });
279
+ console.log("XSkills Connector is disconnected.");
280
+ }
281
+ async function update() {
282
+ requireMac();
283
+ await copyRuntime();
284
+ const config = await readConfig();
285
+ const response = await authorizedApi(config, "/api/connector/device", {
286
+ method: "PATCH",
287
+ body: JSON.stringify({ connectorVersion: VERSION }),
288
+ });
289
+ if (!response.ok)
290
+ throw new Error("Could not register the connector update. Pair this Mac again if the problem continues.");
291
+ await writeFile(CONFIG_PATH, `${JSON.stringify({ ...config, connectorVersion: VERSION }, null, 2)}\n`, { mode: 0o600 });
292
+ await installLaunchAgent();
293
+ console.log(`XSkills Connector updated to ${VERSION}.`);
294
+ }
295
+ const command = process.argv[2];
296
+ try {
297
+ if (command === "install")
298
+ await install();
299
+ else if (command === "run")
300
+ await run();
301
+ else if (command === "status")
302
+ await status();
303
+ else if (command === "disconnect")
304
+ await disconnect();
305
+ else if (command === "update")
306
+ await update();
307
+ else {
308
+ console.log("Usage: xskills <install|run|status|update|disconnect> [--harness codex|claude-code|cursor] [--app https://xskills.app]");
309
+ process.exitCode = command ? 1 : 0;
310
+ }
311
+ }
312
+ catch (error) {
313
+ console.error(error instanceof Error ? error.message : error);
314
+ process.exitCode = 1;
315
+ }
316
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { constants } from "node:fs";
3
+ import { access, mkdir, readFile, realpath, rename, rm, writeFile, } from "node:fs/promises";
4
+ import { homedir } from "node:os";
5
+ import { dirname, join, resolve, sep } from "node:path";
6
+ export const INSTALL_ROOTS = {
7
+ "claude-code": join(homedir(), ".claude", "skills"),
8
+ codex: join(homedir(), ".agents", "skills"),
9
+ cursor: join(homedir(), ".cursor", "skills"),
10
+ };
11
+ const ALLOWED_FILE = /^(?:SKILL\.md|manifest\.json|references\/[a-z0-9._-]+\.md|agents\/openai\.yaml|eval_queries\.json|scripts\/[a-z0-9._/-]+)$/;
12
+ export class InstallError extends Error {
13
+ retryable;
14
+ constructor(message, retryable = false) {
15
+ super(message);
16
+ this.retryable = retryable;
17
+ }
18
+ }
19
+ export function sha256(value) {
20
+ return createHash("sha256").update(value).digest("hex");
21
+ }
22
+ export function packageChecksum(files) {
23
+ const canonical = [...files]
24
+ .sort((a, b) => a.path.localeCompare(b.path))
25
+ .map((file) => [file.path, file.sha256, Buffer.byteLength(file.content)]);
26
+ return sha256(JSON.stringify(canonical));
27
+ }
28
+ export function validateJob(job, config) {
29
+ if (!job ||
30
+ job.harness !== config.harness ||
31
+ !job.package ||
32
+ !Array.isArray(job.package.files))
33
+ throw new InstallError("Package harness does not match this connector.");
34
+ if (!/^[a-z0-9][a-z0-9-]{0,119}$/.test(job.package.slug))
35
+ throw new InstallError("Package slug is unsafe.");
36
+ let total = 0;
37
+ const seen = new Set();
38
+ for (const file of job.package.files) {
39
+ if (!ALLOWED_FILE.test(file.path) ||
40
+ file.path.includes("..") ||
41
+ file.path.startsWith("/") ||
42
+ file.path.includes("\\") ||
43
+ seen.has(file.path))
44
+ throw new InstallError(`Unsafe package path: ${file.path}`);
45
+ seen.add(file.path);
46
+ const size = Buffer.byteLength(file.content);
47
+ total += size;
48
+ if (size > 256 * 1024 || sha256(file.content) !== file.sha256)
49
+ throw new InstallError(`File checksum failed: ${file.path}`);
50
+ }
51
+ if (total > 1024 * 1024)
52
+ throw new InstallError("Package exceeds 1 MiB.");
53
+ if (packageChecksum(job.package.files) !== job.package.checksum)
54
+ throw new InstallError("Package checksum failed.");
55
+ }
56
+ async function directoryMatches(target, files) {
57
+ try {
58
+ for (const file of files)
59
+ if (sha256(await readFile(join(target, file.path))) !== file.sha256)
60
+ return false;
61
+ return true;
62
+ }
63
+ catch {
64
+ return false;
65
+ }
66
+ }
67
+ export async function installJob(job, config) {
68
+ validateJob(job, config);
69
+ const root = config.installRoot ?? INSTALL_ROOTS[config.harness];
70
+ await mkdir(root, { recursive: true, mode: 0o700 });
71
+ const canonicalRoot = await realpath(root);
72
+ const target = resolve(canonicalRoot, job.package.slug);
73
+ if (!target.startsWith(`${canonicalRoot}${sep}`))
74
+ throw new InstallError("Install target escaped the harness root.");
75
+ let existing = false;
76
+ try {
77
+ await access(target, constants.F_OK);
78
+ existing = true;
79
+ }
80
+ catch {
81
+ /* New install. */
82
+ }
83
+ if (existing) {
84
+ if (await directoryMatches(target, job.package.files))
85
+ return { status: "already_installed", location: target };
86
+ try {
87
+ const manifest = JSON.parse(await readFile(join(target, "manifest.json"), "utf8"));
88
+ if (manifest.skill_id !== job.package.skillId)
89
+ throw new InstallError(`A different skill already exists at ${target}.`);
90
+ }
91
+ catch (error) {
92
+ if (error instanceof InstallError)
93
+ throw error;
94
+ throw new InstallError(`XSkills will not overwrite an unmanaged directory at ${target}.`);
95
+ }
96
+ }
97
+ const temporary = join(canonicalRoot, `.${job.package.slug}.xskills-${randomUUID()}.tmp`);
98
+ const backup = join(canonicalRoot, `.${job.package.slug}.xskills-${randomUUID()}.bak`);
99
+ await mkdir(temporary, { recursive: false, mode: 0o700 });
100
+ try {
101
+ for (const file of job.package.files) {
102
+ const destination = join(temporary, file.path);
103
+ await mkdir(dirname(destination), { recursive: true, mode: 0o700 });
104
+ await writeFile(destination, file.content, { mode: 0o600, flag: "wx" });
105
+ }
106
+ if (existing)
107
+ await rename(target, backup);
108
+ try {
109
+ await rename(temporary, target);
110
+ }
111
+ catch (error) {
112
+ if (existing)
113
+ await rename(backup, target);
114
+ throw error;
115
+ }
116
+ if (existing)
117
+ await rm(backup, { recursive: true, force: true });
118
+ return { status: "installed", location: target };
119
+ }
120
+ catch (error) {
121
+ await rm(temporary, { recursive: true, force: true });
122
+ if (error instanceof InstallError)
123
+ throw error;
124
+ const code = error instanceof Error && "code" in error
125
+ ? String(error.code)
126
+ : "";
127
+ throw new InstallError(error instanceof Error ? error.message : "Installation failed", !["EACCES", "EPERM", "EROFS", "ENOSPC"].includes(code));
128
+ }
129
+ }
130
+ //# sourceMappingURL=installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@xskills/connector",
3
+ "version": "0.1.0",
4
+ "description": "Install checksum-approved XSkills packages into local agent harnesses.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "agent-skills",
8
+ "codex",
9
+ "claude-code",
10
+ "cursor"
11
+ ],
12
+ "homepage": "https://github.com/kylerzanuck-work/xskillsai#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/kylerzanuck-work/xskillsai/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/kylerzanuck-work/xskillsai.git",
19
+ "directory": "packages/connector"
20
+ },
21
+ "type": "module",
22
+ "bin": {
23
+ "xskills": "dist/cli.js"
24
+ },
25
+ "files": [
26
+ "dist/cli.js",
27
+ "dist/cli.js.map",
28
+ "dist/installer.js",
29
+ "dist/installer.js.map"
30
+ ],
31
+ "engines": {
32
+ "node": ">=22"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20",
39
+ "typescript": "^5",
40
+ "vitest": "^4.1.10"
41
+ },
42
+ "scripts": {
43
+ "build": "tsc -p tsconfig.json",
44
+ "typecheck": "tsc -p tsconfig.json --noEmit",
45
+ "test": "vitest run src/installer.test.ts"
46
+ }
47
+ }