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.
- package/dist/env/index.d.ts +2 -0
- package/dist/env/index.js +4 -0
- package/dist/env-BUegcU7a.js +392 -0
- package/dist/git/index.d.ts +2 -0
- package/dist/git/index.js +3 -0
- package/dist/git-D4ZclaF6.js +132 -0
- package/dist/index-BW91Ai1Y.d.ts +43 -0
- package/dist/index-CFwFmDD-.d.ts +40 -0
- package/dist/index-CirIJDiq.d.ts +34 -0
- package/dist/index-DmiDvQ8Q.d.ts +37 -0
- package/dist/index-DwU61LUW.d.ts +43 -0
- package/dist/index-LzafUiEo.d.ts +29 -0
- package/dist/index-y5JZ6STt.d.ts +36 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +10 -0
- package/dist/link/index.d.ts +2 -0
- package/dist/link/index.js +3 -0
- package/dist/link-C4PSDr4v.js +199 -0
- package/dist/lock/index.d.ts +2 -0
- package/dist/lock/index.js +3 -0
- package/dist/lock-BeR43Izo.js +108 -0
- package/dist/path-nPuHl-f5.js +21 -0
- package/dist/skill/index.d.ts +2 -0
- package/dist/skill/index.js +3 -0
- package/dist/skill-BmLJYiQz.js +69 -0
- package/dist/source/index.d.ts +2 -0
- package/dist/source/index.js +3 -0
- package/dist/source-IfQxnt_F.js +132 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils-CDyPZons.js +62 -0
- package/package.json +82 -0
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
|
@@ -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,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 };
|