unagent 0.0.1

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,37 @@
1
+ //#region src/source/providers.d.ts
2
+ type SourceProvider = "github" | "gitlab" | "bitbucket" | "local" | "url";
3
+ interface ProviderInfo {
4
+ provider: SourceProvider;
5
+ owner?: string;
6
+ repo?: string;
7
+ path?: string;
8
+ ref?: string;
9
+ url?: string;
10
+ }
11
+ declare function getProviderFromUrl(url: string): SourceProvider;
12
+ declare function parseGitHubUrl(url: string): ProviderInfo | undefined;
13
+ declare function parseGitLabUrl(url: string): ProviderInfo | undefined;
14
+ declare function buildGitHubCloneUrl(owner: string, repo: string): string;
15
+ declare function buildGitLabCloneUrl(owner: string, repo: string): string;
16
+ //#endregion
17
+ //#region src/source/parse.d.ts
18
+ interface ParsedSource {
19
+ type: SourceProvider;
20
+ raw: string;
21
+ owner?: string;
22
+ repo?: string;
23
+ path?: string;
24
+ ref?: string;
25
+ url?: string;
26
+ isLocal: boolean;
27
+ }
28
+ declare function isLocalPath(source: string): boolean;
29
+ declare function isUrl(source: string): boolean;
30
+ declare function parseSource(source: string): ParsedSource;
31
+ declare function getOwnerRepo(parsed: ParsedSource): string | undefined;
32
+ declare function parseOwnerRepo(ownerRepo: string): {
33
+ owner: string;
34
+ repo: string;
35
+ } | undefined;
36
+ //#endregion
37
+ export { parseOwnerRepo as a, SourceProvider as c, getProviderFromUrl as d, parseGitHubUrl as f, isUrl as i, buildGitHubCloneUrl as l, getOwnerRepo as n, parseSource as o, parseGitLabUrl as p, isLocalPath as r, ProviderInfo as s, ParsedSource as t, buildGitLabCloneUrl as u };
@@ -0,0 +1,43 @@
1
+ //#region src/git/clone.d.ts
2
+ declare class GitCloneError extends Error {
3
+ readonly url: string;
4
+ readonly cause: Error | undefined;
5
+ constructor(message: string, url: string, cause?: Error);
6
+ }
7
+ interface CloneOptions {
8
+ depth?: number;
9
+ branch?: string;
10
+ timeout?: number;
11
+ tempDir?: string;
12
+ }
13
+ interface CloneResult {
14
+ success: boolean;
15
+ path: string;
16
+ error?: string;
17
+ }
18
+ declare function cloneRepo(url: string, dest: string, options?: CloneOptions): Promise<CloneResult>;
19
+ declare function cloneToTemp(url: string, options?: CloneOptions): Promise<CloneResult>;
20
+ declare function cleanupTempDir(path: string): boolean;
21
+ declare function isTempDir(path: string): boolean;
22
+ //#endregion
23
+ //#region src/git/operations.d.ts
24
+ interface GitStatus {
25
+ isRepo: boolean;
26
+ branch: string;
27
+ ahead: number;
28
+ behind: number;
29
+ staged: string[];
30
+ modified: string[];
31
+ untracked: string[];
32
+ hasChanges: boolean;
33
+ }
34
+ declare function getGitStatus(dir: string): Promise<GitStatus | undefined>;
35
+ declare function getCurrentBranch(dir: string): Promise<string | undefined>;
36
+ declare function checkout(dir: string, ref: string): Promise<boolean>;
37
+ declare function pull(dir: string): Promise<boolean>;
38
+ declare function fetch(dir: string, remote?: string): Promise<boolean>;
39
+ declare function getRemoteUrl(dir: string, remote?: string): Promise<string | undefined>;
40
+ declare function getLatestCommitHash(dir: string): Promise<string | undefined>;
41
+ declare function hasUncommittedChanges(dir: string): Promise<boolean>;
42
+ //#endregion
43
+ export { getGitStatus as a, hasUncommittedChanges as c, CloneResult as d, GitCloneError as f, isTempDir as g, cloneToTemp as h, getCurrentBranch as i, pull as l, cloneRepo as m, checkout as n, getLatestCommitHash as o, cleanupTempDir as p, fetch as r, getRemoteUrl as s, GitStatus as t, CloneOptions as u };
@@ -0,0 +1,29 @@
1
+ //#region src/lock/hash.d.ts
2
+ declare function computeContentHash(content: string): string;
3
+ declare function computeFileHash(filePath: string): string | undefined;
4
+ declare function computeDirectoryHash(dirPath: string, exclude?: string[]): string | undefined;
5
+ //#endregion
6
+ //#region src/lock/lock.d.ts
7
+ interface SkillLockEntry {
8
+ name: string;
9
+ source: string;
10
+ version?: string;
11
+ hash: string;
12
+ installedAt: string;
13
+ updatedAt: string;
14
+ }
15
+ interface SkillLock {
16
+ version: number;
17
+ skills: Record<string, SkillLockEntry>;
18
+ }
19
+ declare function createEmptyLock(): SkillLock;
20
+ declare function readSkillLock(dir: string, filename?: string): SkillLock;
21
+ declare function writeSkillLock(dir: string, lock: SkillLock, filename?: string): boolean;
22
+ declare function addSkillToLock(lock: SkillLock, id: string, entry: Omit<SkillLockEntry, "installedAt" | "updatedAt">): SkillLock;
23
+ declare function removeSkillFromLock(lock: SkillLock, id: string): SkillLock;
24
+ declare function getSkillFromLock(lock: SkillLock, id: string): SkillLockEntry | undefined;
25
+ declare function hasSkillInLock(lock: SkillLock, id: string): boolean;
26
+ declare function listSkillsInLock(lock: SkillLock): SkillLockEntry[];
27
+ declare function isSkillOutdated(lock: SkillLock, id: string, currentHash: string): boolean;
28
+ //#endregion
29
+ export { getSkillFromLock as a, listSkillsInLock as c, writeSkillLock as d, computeContentHash as f, createEmptyLock as i, readSkillLock as l, computeFileHash as m, SkillLockEntry as n, hasSkillInLock as o, computeDirectoryHash as p, addSkillToLock as r, isSkillOutdated as s, SkillLock as t, removeSkillFromLock as u };
@@ -0,0 +1,36 @@
1
+ //#region src/skill/parse.d.ts
2
+ interface SkillFrontmatter {
3
+ name?: string;
4
+ description?: string;
5
+ version?: string;
6
+ author?: string;
7
+ globs?: string | string[];
8
+ alwaysApply?: boolean;
9
+ tags?: string[];
10
+ [key: string]: unknown;
11
+ }
12
+ interface ParsedSkill {
13
+ frontmatter: SkillFrontmatter;
14
+ content: string;
15
+ raw: string;
16
+ }
17
+ declare function parseSkillMd(content: string): ParsedSkill;
18
+ declare function extractSkillName(frontmatter: SkillFrontmatter, filename?: string): string;
19
+ declare function validateSkillMd(parsed: ParsedSkill): string[];
20
+ //#endregion
21
+ //#region src/skill/discover.d.ts
22
+ interface DiscoveredSkill {
23
+ path: string;
24
+ filename: string;
25
+ name: string;
26
+ parsed: ParsedSkill;
27
+ }
28
+ interface DiscoverOptions {
29
+ recursive?: boolean;
30
+ extensions?: string[];
31
+ }
32
+ declare function discoverSkills(dir: string, options?: DiscoverOptions): DiscoveredSkill[];
33
+ declare function filterSkills(skills: DiscoveredSkill[], query: string): DiscoveredSkill[];
34
+ declare function findSkillByName(skills: DiscoveredSkill[], name: string): DiscoveredSkill | undefined;
35
+ //#endregion
36
+ export { findSkillByName as a, extractSkillName as c, filterSkills as i, parseSkillMd as l, DiscoveredSkill as n, ParsedSkill as o, discoverSkills as r, SkillFrontmatter as s, DiscoverOptions as t, validateSkillMd as u };
@@ -0,0 +1,8 @@
1
+ import { _ as getAgentConfig, a as getAgentSkillsDir, c as isCI, d as detectAgentByEnv, f as detectCurrentAgent, g as agents, h as AgentConfig, i as getAgentRulesPath, l as isTTY, m as isRunningInAgent, n as agentConfigExists, o as getXDGPaths, p as detectInstalledAgents, r as getAgentConfigDir, s as hasTTY, t as XDGPaths, u as DetectedAgent, v as getAgentIds, y as getAllAgents } from "./index-BW91Ai1Y.js";
2
+ import { a as getGitStatus, c as hasUncommittedChanges, d as CloneResult, f as GitCloneError, g as isTempDir, h as cloneToTemp, i as getCurrentBranch, l as pull, m as cloneRepo, n as checkout, o as getLatestCommitHash, p as cleanupTempDir, r as fetch, s as getRemoteUrl, t as GitStatus, u as CloneOptions } from "./index-DwU61LUW.js";
3
+ import { a as removeSymlink, c as validateSymlinkTarget, d as copyDirectory, f as copyFile, i as isSymlink, l as CopyOptions, n as SymlinkResult, o as isPathSafe, p as getDirectorySize, r as createSymlink, s as sanitizeName, t as SymlinkOptions, u as CopyResult } from "./index-CFwFmDD-.js";
4
+ import { a as getSkillFromLock, c as listSkillsInLock, d as writeSkillLock, f as computeContentHash, i as createEmptyLock, l as readSkillLock, m as computeFileHash, n as SkillLockEntry, o as hasSkillInLock, p as computeDirectoryHash, r as addSkillToLock, s as isSkillOutdated, t as SkillLock, u as removeSkillFromLock } from "./index-LzafUiEo.js";
5
+ import { a as findSkillByName, c as extractSkillName, i as filterSkills, l as parseSkillMd, n as DiscoveredSkill, o as ParsedSkill, r as discoverSkills, s as SkillFrontmatter, t as DiscoverOptions, u as validateSkillMd } from "./index-y5JZ6STt.js";
6
+ import { a as parseOwnerRepo, c as SourceProvider, d as getProviderFromUrl, f as parseGitHubUrl, i as isUrl, l as buildGitHubCloneUrl, n as getOwnerRepo, o as parseSource, p as parseGitLabUrl, r as isLocalPath, s as ProviderInfo, t as ParsedSource, u as buildGitLabCloneUrl } from "./index-DmiDvQ8Q.js";
7
+ import { a as truncate, c as bold, d as gray, f as green, h as yellow, i as pluralize, l as cyan, m as stripAnsi, n as shortenPath, o as ANSI, p as red, r as formatList, s as blue, t as expandPath, u as dim } from "./index-CirIJDiq.js";
8
+ export { ANSI, AgentConfig, CloneOptions, CloneResult, CopyOptions, CopyResult, DetectedAgent, DiscoverOptions, DiscoveredSkill, GitCloneError, GitStatus, ParsedSkill, ParsedSource, ProviderInfo, SkillFrontmatter, SkillLock, SkillLockEntry, SourceProvider, SymlinkOptions, SymlinkResult, XDGPaths, addSkillToLock, agentConfigExists, agents, blue, bold, buildGitHubCloneUrl, buildGitLabCloneUrl, checkout, cleanupTempDir, cloneRepo, cloneToTemp, computeContentHash, computeDirectoryHash, computeFileHash, copyDirectory, copyFile, createEmptyLock, createSymlink, cyan, detectAgentByEnv, detectCurrentAgent, detectInstalledAgents, dim, discoverSkills, expandPath, extractSkillName, fetch, filterSkills, findSkillByName, formatList, getAgentConfig, getAgentConfigDir, getAgentIds, getAgentRulesPath, getAgentSkillsDir, getAllAgents, getCurrentBranch, getDirectorySize, getGitStatus, getLatestCommitHash, getOwnerRepo, getProviderFromUrl, getRemoteUrl, getSkillFromLock, getXDGPaths, gray, green, hasSkillInLock, hasTTY, hasUncommittedChanges, isCI, isLocalPath, isPathSafe, isRunningInAgent, isSkillOutdated, isSymlink, isTTY, isTempDir, isUrl, listSkillsInLock, parseGitHubUrl, parseGitLabUrl, parseOwnerRepo, parseSkillMd, parseSource, pluralize, pull, readSkillLock, red, removeSkillFromLock, removeSymlink, sanitizeName, shortenPath, stripAnsi, truncate, validateSkillMd, validateSymlinkTarget, writeSkillLock, yellow };
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ import { a as agentConfigExists, c as getAgentSkillsDir, d as isCI, f as isTTY, g as getAllAgents, h as getAgentIds, i as isRunningInAgent, l as getXDGPaths, m as getAgentConfig, n as detectCurrentAgent, o as getAgentConfigDir, p as agents, r as detectInstalledAgents, s as getAgentRulesPath, t as detectAgentByEnv, u as hasTTY } from "./env-BUegcU7a.js";
2
+ import { n as shortenPath, t as expandPath } from "./path-nPuHl-f5.js";
3
+ import { a as getLatestCommitHash, c as pull, d as cloneRepo, f as cloneToTemp, i as getGitStatus, l as GitCloneError, n as fetch, o as getRemoteUrl, p as isTempDir, r as getCurrentBranch, s as hasUncommittedChanges, t as checkout, u as cleanupTempDir } from "./git-D4ZclaF6.js";
4
+ import { a as sanitizeName, c as copyFile, i as isPathSafe, l as getDirectorySize, n as isSymlink, o as validateSymlinkTarget, r as removeSymlink, s as copyDirectory, t as createSymlink } from "./link-C4PSDr4v.js";
5
+ import { a as isSkillOutdated, c as removeSkillFromLock, d as computeDirectoryHash, f as computeFileHash, i as hasSkillInLock, l as writeSkillLock, n as createEmptyLock, o as listSkillsInLock, r as getSkillFromLock, s as readSkillLock, t as addSkillToLock, u as computeContentHash } from "./lock-BeR43Izo.js";
6
+ import { a as parseSkillMd, i as extractSkillName, n as filterSkills, o as validateSkillMd, r as findSkillByName, t as discoverSkills } from "./skill-BmLJYiQz.js";
7
+ import { a as parseSource, c as getProviderFromUrl, i as parseOwnerRepo, l as parseGitHubUrl, n as isLocalPath, o as buildGitHubCloneUrl, r as isUrl, s as buildGitLabCloneUrl, t as getOwnerRepo, u as parseGitLabUrl } from "./source-IfQxnt_F.js";
8
+ import { a as blue, c as dim, d as red, f as stripAnsi, i as ANSI, l as gray, n as pluralize, o as bold, p as yellow, r as truncate, s as cyan, t as formatList, u as green } from "./utils-CDyPZons.js";
9
+
10
+ export { ANSI, GitCloneError, addSkillToLock, agentConfigExists, agents, blue, bold, buildGitHubCloneUrl, buildGitLabCloneUrl, checkout, cleanupTempDir, cloneRepo, cloneToTemp, computeContentHash, computeDirectoryHash, computeFileHash, copyDirectory, copyFile, createEmptyLock, createSymlink, cyan, detectAgentByEnv, detectCurrentAgent, detectInstalledAgents, dim, discoverSkills, expandPath, extractSkillName, fetch, filterSkills, findSkillByName, formatList, getAgentConfig, getAgentConfigDir, getAgentIds, getAgentRulesPath, getAgentSkillsDir, getAllAgents, getCurrentBranch, getDirectorySize, getGitStatus, getLatestCommitHash, getOwnerRepo, getProviderFromUrl, getRemoteUrl, getSkillFromLock, getXDGPaths, gray, green, hasSkillInLock, hasTTY, hasUncommittedChanges, isCI, isLocalPath, isPathSafe, isRunningInAgent, isSkillOutdated, isSymlink, isTTY, isTempDir, isUrl, listSkillsInLock, parseGitHubUrl, parseGitLabUrl, parseOwnerRepo, parseSkillMd, parseSource, pluralize, pull, readSkillLock, red, removeSkillFromLock, removeSymlink, sanitizeName, shortenPath, stripAnsi, truncate, validateSkillMd, validateSymlinkTarget, writeSkillLock, yellow };
@@ -0,0 +1,2 @@
1
+ import { a as removeSymlink, c as validateSymlinkTarget, d as copyDirectory, f as copyFile, i as isSymlink, l as CopyOptions, n as SymlinkResult, o as isPathSafe, p as getDirectorySize, r as createSymlink, s as sanitizeName, t as SymlinkOptions, u as CopyResult } from "../index-CFwFmDD-.js";
2
+ export { CopyOptions, CopyResult, SymlinkOptions, SymlinkResult, copyDirectory, copyFile, createSymlink, getDirectorySize, isPathSafe, isSymlink, removeSymlink, sanitizeName, validateSymlinkTarget };
@@ -0,0 +1,3 @@
1
+ import { a as sanitizeName, c as copyFile, i as isPathSafe, l as getDirectorySize, n as isSymlink, o as validateSymlinkTarget, r as removeSymlink, s as copyDirectory, t as createSymlink } from "../link-C4PSDr4v.js";
2
+
3
+ export { copyDirectory, copyFile, createSymlink, getDirectorySize, isPathSafe, isSymlink, removeSymlink, sanitizeName, validateSymlinkTarget };
@@ -0,0 +1,199 @@
1
+ import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, rmSync, statSync, symlinkSync, unlinkSync } from "node:fs";
2
+ import { dirname, isAbsolute, join, normalize, relative, resolve } from "pathe";
3
+
4
+ //#region src/link/copy.ts
5
+ const DEFAULT_EXCLUDE = [
6
+ ".git",
7
+ "node_modules",
8
+ ".DS_Store",
9
+ "Thumbs.db"
10
+ ];
11
+ function copyDirectory(src, dest, options = {}) {
12
+ const { force = false, exclude = DEFAULT_EXCLUDE, preserveTimestamps = true } = options;
13
+ if (!existsSync(src)) return {
14
+ success: false,
15
+ src,
16
+ dest,
17
+ error: "Source does not exist"
18
+ };
19
+ if (!statSync(src).isDirectory()) return {
20
+ success: false,
21
+ src,
22
+ dest,
23
+ error: "Source is not a directory"
24
+ };
25
+ try {
26
+ if (existsSync(dest)) {
27
+ if (!force) return {
28
+ success: false,
29
+ src,
30
+ dest,
31
+ error: "Destination already exists"
32
+ };
33
+ rmSync(dest, {
34
+ recursive: true,
35
+ force: true
36
+ });
37
+ }
38
+ mkdirSync(dest, { recursive: true });
39
+ return {
40
+ success: true,
41
+ src,
42
+ dest,
43
+ filesCopied: copyRecursive(src, dest, exclude, preserveTimestamps)
44
+ };
45
+ } catch (error) {
46
+ return {
47
+ success: false,
48
+ src,
49
+ dest,
50
+ error: error instanceof Error ? error.message : "Unknown error"
51
+ };
52
+ }
53
+ }
54
+ function copyRecursive(src, dest, exclude, preserveTimestamps) {
55
+ let count = 0;
56
+ const entries = readdirSync(src);
57
+ for (const entry of entries) {
58
+ if (exclude.includes(entry)) continue;
59
+ const srcPath = join(src, entry);
60
+ const destPath = join(dest, entry);
61
+ if (statSync(srcPath).isDirectory()) {
62
+ mkdirSync(destPath, { recursive: true });
63
+ count += copyRecursive(srcPath, destPath, exclude, preserveTimestamps);
64
+ } else {
65
+ cpSync(srcPath, destPath, { preserveTimestamps });
66
+ count++;
67
+ }
68
+ }
69
+ return count;
70
+ }
71
+ function copyFile(src, dest, options = {}) {
72
+ const { force = false } = options;
73
+ if (!existsSync(src)) return false;
74
+ if (existsSync(dest) && !force) return false;
75
+ try {
76
+ const destDir = join(dest, "..");
77
+ if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });
78
+ cpSync(src, dest);
79
+ return true;
80
+ } catch {
81
+ return false;
82
+ }
83
+ }
84
+ function getDirectorySize(dir) {
85
+ if (!existsSync(dir)) return 0;
86
+ let size = 0;
87
+ const entries = readdirSync(dir);
88
+ for (const entry of entries) {
89
+ const fullPath = join(dir, entry);
90
+ const stat = statSync(fullPath);
91
+ if (stat.isDirectory()) size += getDirectorySize(fullPath);
92
+ else size += stat.size;
93
+ }
94
+ return size;
95
+ }
96
+
97
+ //#endregion
98
+ //#region src/link/sanitize.ts
99
+ function sanitizeName(name) {
100
+ return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 100);
101
+ }
102
+ function isPathSafe(targetPath, baseDir) {
103
+ const resolved = resolve(baseDir, targetPath);
104
+ const normalizedBase = normalize(baseDir);
105
+ if (!normalize(resolved).startsWith(normalizedBase)) return false;
106
+ const rel = relative(baseDir, resolved);
107
+ if (rel.startsWith("..") || isAbsolute(rel)) return false;
108
+ if ([
109
+ "..",
110
+ "~",
111
+ "$",
112
+ "`",
113
+ "|",
114
+ ";",
115
+ "&",
116
+ ">",
117
+ "<",
118
+ "\\"
119
+ ].some((char) => targetPath.includes(char))) return false;
120
+ return true;
121
+ }
122
+ function validateSymlinkTarget(target) {
123
+ if (!target || typeof target !== "string") return false;
124
+ if (target.length > 4096) return false;
125
+ if (target.includes("\0")) return false;
126
+ return true;
127
+ }
128
+
129
+ //#endregion
130
+ //#region src/link/symlink.ts
131
+ function createSymlink(target, linkPath, options = {}) {
132
+ const { force = false, relative: useRelative = true } = options;
133
+ if (!validateSymlinkTarget(target)) return {
134
+ success: false,
135
+ path: linkPath,
136
+ target,
137
+ error: "Invalid symlink target"
138
+ };
139
+ if (!existsSync(target)) return {
140
+ success: false,
141
+ path: linkPath,
142
+ target,
143
+ error: "Target does not exist"
144
+ };
145
+ try {
146
+ const linkDir = dirname(linkPath);
147
+ if (!existsSync(linkDir)) mkdirSync(linkDir, { recursive: true });
148
+ if (existsSync(linkPath)) {
149
+ if (!force) return {
150
+ success: false,
151
+ path: linkPath,
152
+ target,
153
+ error: "Link already exists"
154
+ };
155
+ const stat = lstatSync(linkPath);
156
+ if (stat.isSymbolicLink() || stat.isFile()) unlinkSync(linkPath);
157
+ else return {
158
+ success: false,
159
+ path: linkPath,
160
+ target,
161
+ error: "Cannot overwrite directory"
162
+ };
163
+ }
164
+ const symlinkTarget = useRelative ? relative(linkDir, target) : target;
165
+ const targetStat = lstatSync(target);
166
+ symlinkSync(symlinkTarget, linkPath, process.platform === "win32" && targetStat.isDirectory() ? "junction" : void 0);
167
+ return {
168
+ success: true,
169
+ path: linkPath,
170
+ target
171
+ };
172
+ } catch (error) {
173
+ return {
174
+ success: false,
175
+ path: linkPath,
176
+ target,
177
+ error: error instanceof Error ? error.message : "Unknown error"
178
+ };
179
+ }
180
+ }
181
+ function isSymlink(path) {
182
+ try {
183
+ return lstatSync(path).isSymbolicLink();
184
+ } catch {
185
+ return false;
186
+ }
187
+ }
188
+ function removeSymlink(linkPath) {
189
+ try {
190
+ if (!isSymlink(linkPath)) return false;
191
+ unlinkSync(linkPath);
192
+ return true;
193
+ } catch {
194
+ return false;
195
+ }
196
+ }
197
+
198
+ //#endregion
199
+ export { sanitizeName as a, copyFile as c, isPathSafe as i, getDirectorySize as l, isSymlink as n, validateSymlinkTarget as o, removeSymlink as r, copyDirectory as s, createSymlink as t };
@@ -0,0 +1,2 @@
1
+ import { a as getSkillFromLock, c as listSkillsInLock, d as writeSkillLock, f as computeContentHash, i as createEmptyLock, l as readSkillLock, m as computeFileHash, n as SkillLockEntry, o as hasSkillInLock, p as computeDirectoryHash, r as addSkillToLock, s as isSkillOutdated, t as SkillLock, u as removeSkillFromLock } from "../index-LzafUiEo.js";
2
+ export { SkillLock, SkillLockEntry, addSkillToLock, computeContentHash, computeDirectoryHash, computeFileHash, createEmptyLock, getSkillFromLock, hasSkillInLock, isSkillOutdated, listSkillsInLock, readSkillLock, removeSkillFromLock, writeSkillLock };
@@ -0,0 +1,3 @@
1
+ import { a as isSkillOutdated, c as removeSkillFromLock, d as computeDirectoryHash, f as computeFileHash, i as hasSkillInLock, l as writeSkillLock, n as createEmptyLock, o as listSkillsInLock, r as getSkillFromLock, s as readSkillLock, t as addSkillToLock, u as computeContentHash } from "../lock-BeR43Izo.js";
2
+
3
+ export { addSkillToLock, computeContentHash, computeDirectoryHash, computeFileHash, createEmptyLock, getSkillFromLock, hasSkillInLock, isSkillOutdated, listSkillsInLock, readSkillLock, removeSkillFromLock, writeSkillLock };
@@ -0,0 +1,108 @@
1
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "pathe";
3
+ import { createHash } from "node:crypto";
4
+
5
+ //#region src/lock/hash.ts
6
+ function computeContentHash(content) {
7
+ return createHash("sha256").update(content).digest("hex").slice(0, 16);
8
+ }
9
+ function computeFileHash(filePath) {
10
+ if (!existsSync(filePath)) return void 0;
11
+ return computeContentHash(readFileSync(filePath, "utf-8"));
12
+ }
13
+ function computeDirectoryHash(dirPath, exclude = []) {
14
+ if (!existsSync(dirPath)) return void 0;
15
+ const hash = createHash("sha256");
16
+ hashDirectory(dirPath, hash, exclude);
17
+ return hash.digest("hex").slice(0, 16);
18
+ }
19
+ function hashDirectory(dir, hash, exclude) {
20
+ const entries = readdirSync(dir).sort();
21
+ for (const entry of entries) {
22
+ if (exclude.includes(entry)) continue;
23
+ const fullPath = join(dir, entry);
24
+ const stat = statSync(fullPath);
25
+ hash.update(entry);
26
+ if (stat.isDirectory()) {
27
+ hash.update("dir");
28
+ hashDirectory(fullPath, hash, exclude);
29
+ } else {
30
+ hash.update("file");
31
+ const content = readFileSync(fullPath);
32
+ hash.update(content);
33
+ }
34
+ }
35
+ }
36
+
37
+ //#endregion
38
+ //#region src/lock/lock.ts
39
+ const LOCK_VERSION = 1;
40
+ const DEFAULT_LOCK_FILE = "skill.lock";
41
+ function createEmptyLock() {
42
+ return {
43
+ version: LOCK_VERSION,
44
+ skills: {}
45
+ };
46
+ }
47
+ function readSkillLock(dir, filename = DEFAULT_LOCK_FILE) {
48
+ const lockPath = join(dir, filename);
49
+ if (!existsSync(lockPath)) return createEmptyLock();
50
+ try {
51
+ const content = readFileSync(lockPath, "utf-8");
52
+ const lock = JSON.parse(content);
53
+ if (lock.version !== LOCK_VERSION) return createEmptyLock();
54
+ return lock;
55
+ } catch {
56
+ return createEmptyLock();
57
+ }
58
+ }
59
+ function writeSkillLock(dir, lock, filename = DEFAULT_LOCK_FILE) {
60
+ const lockPath = join(dir, filename);
61
+ try {
62
+ const lockDir = dirname(lockPath);
63
+ if (!existsSync(lockDir)) mkdirSync(lockDir, { recursive: true });
64
+ writeFileSync(lockPath, JSON.stringify(lock, null, 2), "utf-8");
65
+ return true;
66
+ } catch {
67
+ return false;
68
+ }
69
+ }
70
+ function addSkillToLock(lock, id, entry) {
71
+ const now = (/* @__PURE__ */ new Date()).toISOString();
72
+ const existing = lock.skills[id];
73
+ return {
74
+ ...lock,
75
+ skills: {
76
+ ...lock.skills,
77
+ [id]: {
78
+ ...entry,
79
+ installedAt: existing?.installedAt || now,
80
+ updatedAt: now
81
+ }
82
+ }
83
+ };
84
+ }
85
+ function removeSkillFromLock(lock, id) {
86
+ const { [id]: _,...rest } = lock.skills;
87
+ return {
88
+ ...lock,
89
+ skills: rest
90
+ };
91
+ }
92
+ function getSkillFromLock(lock, id) {
93
+ return lock.skills[id];
94
+ }
95
+ function hasSkillInLock(lock, id) {
96
+ return id in lock.skills;
97
+ }
98
+ function listSkillsInLock(lock) {
99
+ return Object.values(lock.skills);
100
+ }
101
+ function isSkillOutdated(lock, id, currentHash) {
102
+ const entry = lock.skills[id];
103
+ if (!entry) return true;
104
+ return entry.hash !== currentHash;
105
+ }
106
+
107
+ //#endregion
108
+ export { isSkillOutdated as a, removeSkillFromLock as c, computeDirectoryHash as d, computeFileHash as f, hasSkillInLock as i, writeSkillLock as l, createEmptyLock as n, listSkillsInLock as o, getSkillFromLock as r, readSkillLock as s, addSkillToLock as t, computeContentHash as u };
@@ -0,0 +1,21 @@
1
+ import { homedir } from "node:os";
2
+ import { relative, resolve } from "pathe";
3
+
4
+ //#region src/utils/path.ts
5
+ function shortenPath(filepath, cwd) {
6
+ const home = homedir();
7
+ const resolved = resolve(filepath);
8
+ if (cwd) {
9
+ const rel = relative(cwd, resolved);
10
+ if (!rel.startsWith("..")) return rel.startsWith(".") ? rel : `./${rel}`;
11
+ }
12
+ if (resolved.startsWith(home)) return `~${resolved.slice(home.length)}`;
13
+ return resolved;
14
+ }
15
+ function expandPath(filepath) {
16
+ if (filepath.startsWith("~")) return `${homedir()}${filepath.slice(1)}`;
17
+ return resolve(filepath);
18
+ }
19
+
20
+ //#endregion
21
+ export { shortenPath as n, expandPath as t };
@@ -0,0 +1,2 @@
1
+ import { a as findSkillByName, c as extractSkillName, i as filterSkills, l as parseSkillMd, n as DiscoveredSkill, o as ParsedSkill, r as discoverSkills, s as SkillFrontmatter, t as DiscoverOptions, u as validateSkillMd } from "../index-y5JZ6STt.js";
2
+ export { DiscoverOptions, DiscoveredSkill, ParsedSkill, SkillFrontmatter, discoverSkills, extractSkillName, filterSkills, findSkillByName, parseSkillMd, validateSkillMd };
@@ -0,0 +1,3 @@
1
+ import { a as parseSkillMd, i as extractSkillName, n as filterSkills, o as validateSkillMd, r as findSkillByName, t as discoverSkills } from "../skill-BmLJYiQz.js";
2
+
3
+ export { discoverSkills, extractSkillName, filterSkills, findSkillByName, parseSkillMd, validateSkillMd };
@@ -0,0 +1,69 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { basename, extname, join } from "pathe";
3
+ import matter from "gray-matter";
4
+
5
+ //#region src/skill/parse.ts
6
+ function parseSkillMd(content) {
7
+ const { data, content: body } = matter(content);
8
+ return {
9
+ frontmatter: data,
10
+ content: body.trim(),
11
+ raw: content
12
+ };
13
+ }
14
+ function extractSkillName(frontmatter, filename) {
15
+ if (frontmatter.name) return frontmatter.name;
16
+ if (filename) return filename.replace(/\.md$/i, "").replace(/^SKILL[._-]?/i, "").replace(/[._-]/g, " ").trim();
17
+ return "Unnamed Skill";
18
+ }
19
+ function validateSkillMd(parsed) {
20
+ const errors = [];
21
+ if (!parsed.content) errors.push("Skill content is empty");
22
+ if (parsed.frontmatter.globs) {
23
+ const globs = Array.isArray(parsed.frontmatter.globs) ? parsed.frontmatter.globs : [parsed.frontmatter.globs];
24
+ for (const glob of globs) if (typeof glob !== "string") errors.push(`Invalid glob pattern: ${glob}`);
25
+ }
26
+ return errors;
27
+ }
28
+
29
+ //#endregion
30
+ //#region src/skill/discover.ts
31
+ const DEFAULT_EXTENSIONS = [".md"];
32
+ function discoverSkills(dir, options = {}) {
33
+ const { recursive = false, extensions = DEFAULT_EXTENSIONS } = options;
34
+ if (!existsSync(dir)) return [];
35
+ const skills = [];
36
+ const entries = readdirSync(dir);
37
+ for (const entry of entries) {
38
+ const fullPath = join(dir, entry);
39
+ const stat = statSync(fullPath);
40
+ if (stat.isDirectory() && recursive) skills.push(...discoverSkills(fullPath, options));
41
+ else if (stat.isFile() && extensions.includes(extname(entry).toLowerCase())) try {
42
+ const parsed = parseSkillMd(readFileSync(fullPath, "utf-8"));
43
+ const filename = basename(entry, extname(entry));
44
+ skills.push({
45
+ path: fullPath,
46
+ filename,
47
+ name: extractSkillName(parsed.frontmatter, filename),
48
+ parsed
49
+ });
50
+ } catch {}
51
+ }
52
+ return skills;
53
+ }
54
+ function filterSkills(skills, query) {
55
+ const lowerQuery = query.toLowerCase();
56
+ return skills.filter((skill) => {
57
+ const nameMatch = skill.name.toLowerCase().includes(lowerQuery);
58
+ const filenameMatch = skill.filename.toLowerCase().includes(lowerQuery);
59
+ const tagMatch = skill.parsed.frontmatter.tags?.some((tag) => tag.toLowerCase().includes(lowerQuery));
60
+ return nameMatch || filenameMatch || tagMatch;
61
+ });
62
+ }
63
+ function findSkillByName(skills, name) {
64
+ const lowerName = name.toLowerCase();
65
+ return skills.find((skill) => skill.name.toLowerCase() === lowerName || skill.filename.toLowerCase() === lowerName);
66
+ }
67
+
68
+ //#endregion
69
+ export { parseSkillMd as a, extractSkillName as i, filterSkills as n, validateSkillMd as o, findSkillByName as r, discoverSkills as t };
@@ -0,0 +1,2 @@
1
+ import { a as parseOwnerRepo, c as SourceProvider, d as getProviderFromUrl, f as parseGitHubUrl, i as isUrl, l as buildGitHubCloneUrl, n as getOwnerRepo, o as parseSource, p as parseGitLabUrl, r as isLocalPath, s as ProviderInfo, t as ParsedSource, u as buildGitLabCloneUrl } from "../index-DmiDvQ8Q.js";
2
+ export { ParsedSource, ProviderInfo, SourceProvider, buildGitHubCloneUrl, buildGitLabCloneUrl, getOwnerRepo, getProviderFromUrl, isLocalPath, isUrl, parseGitHubUrl, parseGitLabUrl, parseOwnerRepo, parseSource };
@@ -0,0 +1,3 @@
1
+ import { a as parseSource, c as getProviderFromUrl, i as parseOwnerRepo, l as parseGitHubUrl, n as isLocalPath, o as buildGitHubCloneUrl, r as isUrl, s as buildGitLabCloneUrl, t as getOwnerRepo, u as parseGitLabUrl } from "../source-IfQxnt_F.js";
2
+
3
+ export { buildGitHubCloneUrl, buildGitLabCloneUrl, getOwnerRepo, getProviderFromUrl, isLocalPath, isUrl, parseGitHubUrl, parseGitLabUrl, parseOwnerRepo, parseSource };