skillex 0.2.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/CHANGELOG.md +64 -0
- package/LICENSE +21 -0
- package/README.md +631 -0
- package/bin/skillex.js +11 -0
- package/dist/adapters.d.ts +60 -0
- package/dist/adapters.js +213 -0
- package/dist/catalog.d.ts +73 -0
- package/dist/catalog.js +356 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.js +885 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.js +25 -0
- package/dist/confirm.d.ts +8 -0
- package/dist/confirm.js +24 -0
- package/dist/fs.d.ts +79 -0
- package/dist/fs.js +184 -0
- package/dist/http.d.ts +43 -0
- package/dist/http.js +123 -0
- package/dist/install.d.ts +115 -0
- package/dist/install.js +895 -0
- package/dist/output.d.ts +46 -0
- package/dist/output.js +78 -0
- package/dist/runner.d.ts +31 -0
- package/dist/runner.js +94 -0
- package/dist/skill.d.ts +23 -0
- package/dist/skill.js +61 -0
- package/dist/sync.d.ts +41 -0
- package/dist/sync.js +384 -0
- package/dist/types.d.ts +442 -0
- package/dist/types.js +83 -0
- package/dist/ui.d.ts +43 -0
- package/dist/ui.js +78 -0
- package/dist/user-config.d.ts +39 -0
- package/dist/user-config.js +54 -0
- package/package.json +93 -0
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { StatePaths } from "./types.js";
|
|
2
|
+
export declare const DEFAULT_AGENT_SKILLS_DIR = ".agent-skills";
|
|
3
|
+
export declare const DEFAULT_LOCKFILE = "skills.json";
|
|
4
|
+
export declare const DEFAULT_LOCAL_SKILLS_DIR = "skills";
|
|
5
|
+
export declare const DEFAULT_GENERATED_DIR = "generated";
|
|
6
|
+
export declare const DEFAULT_CATALOG_PATH = "catalog.json";
|
|
7
|
+
export declare const DEFAULT_SKILLS_DIR = "skills";
|
|
8
|
+
export declare const DEFAULT_REPO = "lgili/skillex";
|
|
9
|
+
export declare const DEFAULT_REF = "main";
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the managed workspace state paths used by Skillex.
|
|
12
|
+
*
|
|
13
|
+
* @param cwd - Workspace root.
|
|
14
|
+
* @param baseDir - Managed local state directory.
|
|
15
|
+
* @returns Absolute paths for the state directory and lockfile.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getStatePaths(cwd: string, baseDir?: string): StatePaths;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
export const DEFAULT_AGENT_SKILLS_DIR = ".agent-skills";
|
|
3
|
+
export const DEFAULT_LOCKFILE = "skills.json";
|
|
4
|
+
export const DEFAULT_LOCAL_SKILLS_DIR = "skills";
|
|
5
|
+
export const DEFAULT_GENERATED_DIR = "generated";
|
|
6
|
+
export const DEFAULT_CATALOG_PATH = "catalog.json";
|
|
7
|
+
export const DEFAULT_SKILLS_DIR = "skills";
|
|
8
|
+
export const DEFAULT_REPO = "lgili/skillex";
|
|
9
|
+
export const DEFAULT_REF = "main";
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the managed workspace state paths used by Skillex.
|
|
12
|
+
*
|
|
13
|
+
* @param cwd - Workspace root.
|
|
14
|
+
* @param baseDir - Managed local state directory.
|
|
15
|
+
* @returns Absolute paths for the state directory and lockfile.
|
|
16
|
+
*/
|
|
17
|
+
export function getStatePaths(cwd, baseDir = DEFAULT_AGENT_SKILLS_DIR) {
|
|
18
|
+
const stateDir = path.resolve(cwd, baseDir);
|
|
19
|
+
return {
|
|
20
|
+
stateDir,
|
|
21
|
+
lockfilePath: path.join(stateDir, DEFAULT_LOCKFILE),
|
|
22
|
+
skillsDirPath: path.join(stateDir, DEFAULT_LOCAL_SKILLS_DIR),
|
|
23
|
+
generatedDirPath: path.join(stateDir, DEFAULT_GENERATED_DIR),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompts the user for a yes/no confirmation in interactive terminals.
|
|
3
|
+
*
|
|
4
|
+
* @param message - Prompt shown to the user.
|
|
5
|
+
* @returns `true` when the user confirms.
|
|
6
|
+
* @throws {CliError} When interactive input is unavailable.
|
|
7
|
+
*/
|
|
8
|
+
export declare function confirmAction(message: string): Promise<boolean>;
|
package/dist/confirm.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
import { CliError } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Prompts the user for a yes/no confirmation in interactive terminals.
|
|
6
|
+
*
|
|
7
|
+
* @param message - Prompt shown to the user.
|
|
8
|
+
* @returns `true` when the user confirms.
|
|
9
|
+
* @throws {CliError} When interactive input is unavailable.
|
|
10
|
+
*/
|
|
11
|
+
export async function confirmAction(message) {
|
|
12
|
+
if (!input.isTTY || !output.isTTY) {
|
|
13
|
+
throw new CliError("Confirmacao interativa indisponivel neste terminal. Use a flag correspondente.", "TTY_REQUIRED");
|
|
14
|
+
}
|
|
15
|
+
const rl = createInterface({ input, output });
|
|
16
|
+
try {
|
|
17
|
+
const answer = await rl.question(`${message} [y/N] `);
|
|
18
|
+
const normalized = answer.trim().toLowerCase();
|
|
19
|
+
return normalized === "y" || normalized === "yes" || normalized === "s" || normalized === "sim";
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
rl.close();
|
|
23
|
+
}
|
|
24
|
+
}
|
package/dist/fs.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { CreateSymlinkResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether a file or directory exists.
|
|
4
|
+
*
|
|
5
|
+
* @param targetPath - Absolute or relative path to probe.
|
|
6
|
+
* @returns `true` when the target exists.
|
|
7
|
+
*/
|
|
8
|
+
export declare function pathExists(targetPath: string): Promise<boolean>;
|
|
9
|
+
/**
|
|
10
|
+
* Ensures that a directory exists.
|
|
11
|
+
*
|
|
12
|
+
* @param dirPath - Directory path to create.
|
|
13
|
+
*/
|
|
14
|
+
export declare function ensureDir(dirPath: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Reads and parses a JSON file, returning a fallback when the file is missing.
|
|
17
|
+
*
|
|
18
|
+
* @param filePath - JSON file path.
|
|
19
|
+
* @param fallback - Value returned for missing files.
|
|
20
|
+
* @returns Parsed JSON content or the fallback value.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readJson<T>(filePath: string, fallback?: T | null): Promise<T | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Reads a UTF-8 text file, returning a fallback when the file is missing.
|
|
25
|
+
*
|
|
26
|
+
* @param filePath - Text file path.
|
|
27
|
+
* @param fallback - Value returned for missing files.
|
|
28
|
+
* @returns File content or the fallback value.
|
|
29
|
+
*/
|
|
30
|
+
export declare function readText(filePath: string, fallback?: string | null): Promise<string | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Writes a JSON value to disk with stable pretty-print formatting.
|
|
33
|
+
*
|
|
34
|
+
* @param filePath - Output file path.
|
|
35
|
+
* @param value - Serializable JSON value.
|
|
36
|
+
*/
|
|
37
|
+
export declare function writeJson(filePath: string, value: unknown): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Writes UTF-8 text content to disk.
|
|
40
|
+
*
|
|
41
|
+
* @param filePath - Output file path.
|
|
42
|
+
* @param value - Text content to write.
|
|
43
|
+
*/
|
|
44
|
+
export declare function writeText(filePath: string, value: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Removes a file or directory recursively when present.
|
|
47
|
+
*
|
|
48
|
+
* @param targetPath - File system path to remove.
|
|
49
|
+
*/
|
|
50
|
+
export declare function removePath(targetPath: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Creates a relative symlink and reports whether the caller should fall back to copy mode.
|
|
53
|
+
*
|
|
54
|
+
* @param targetPath - Absolute path the link should point to.
|
|
55
|
+
* @param linkPath - Absolute path of the symlink to create.
|
|
56
|
+
* @returns Symlink creation result.
|
|
57
|
+
*/
|
|
58
|
+
export declare function createSymlink(targetPath: string, linkPath: string): Promise<CreateSymlinkResult>;
|
|
59
|
+
/**
|
|
60
|
+
* Removes a symlink without following it.
|
|
61
|
+
*
|
|
62
|
+
* @param linkPath - Link path to remove when present.
|
|
63
|
+
*/
|
|
64
|
+
export declare function removeSymlink(linkPath: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Reads a symlink target when the path is a symbolic link.
|
|
67
|
+
*
|
|
68
|
+
* @param linkPath - Candidate link path.
|
|
69
|
+
* @returns Link target or `null` when the path is missing or not a symlink.
|
|
70
|
+
*/
|
|
71
|
+
export declare function readSymlink(linkPath: string): Promise<string | null>;
|
|
72
|
+
/**
|
|
73
|
+
* Validates and normalizes a safe relative path.
|
|
74
|
+
*
|
|
75
|
+
* @param relativePath - Candidate relative path.
|
|
76
|
+
* @returns Normalized POSIX relative path.
|
|
77
|
+
* @throws {ValidationError} When the path is empty, absolute, or escapes the root.
|
|
78
|
+
*/
|
|
79
|
+
export declare function assertSafeRelativePath(relativePath: string): string;
|
package/dist/fs.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { ValidationError } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether a file or directory exists.
|
|
6
|
+
*
|
|
7
|
+
* @param targetPath - Absolute or relative path to probe.
|
|
8
|
+
* @returns `true` when the target exists.
|
|
9
|
+
*/
|
|
10
|
+
export async function pathExists(targetPath) {
|
|
11
|
+
try {
|
|
12
|
+
await fs.access(targetPath);
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Ensures that a directory exists.
|
|
21
|
+
*
|
|
22
|
+
* @param dirPath - Directory path to create.
|
|
23
|
+
*/
|
|
24
|
+
export async function ensureDir(dirPath) {
|
|
25
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Reads and parses a JSON file, returning a fallback when the file is missing.
|
|
29
|
+
*
|
|
30
|
+
* @param filePath - JSON file path.
|
|
31
|
+
* @param fallback - Value returned for missing files.
|
|
32
|
+
* @returns Parsed JSON content or the fallback value.
|
|
33
|
+
*/
|
|
34
|
+
export async function readJson(filePath, fallback = null) {
|
|
35
|
+
try {
|
|
36
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
37
|
+
return JSON.parse(content);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Reads a UTF-8 text file, returning a fallback when the file is missing.
|
|
48
|
+
*
|
|
49
|
+
* @param filePath - Text file path.
|
|
50
|
+
* @param fallback - Value returned for missing files.
|
|
51
|
+
* @returns File content or the fallback value.
|
|
52
|
+
*/
|
|
53
|
+
export async function readText(filePath, fallback = null) {
|
|
54
|
+
try {
|
|
55
|
+
return await fs.readFile(filePath, "utf8");
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
59
|
+
return fallback;
|
|
60
|
+
}
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Writes a JSON value to disk with stable pretty-print formatting.
|
|
66
|
+
*
|
|
67
|
+
* @param filePath - Output file path.
|
|
68
|
+
* @param value - Serializable JSON value.
|
|
69
|
+
*/
|
|
70
|
+
export async function writeJson(filePath, value) {
|
|
71
|
+
await ensureDir(path.dirname(filePath));
|
|
72
|
+
await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Writes UTF-8 text content to disk.
|
|
76
|
+
*
|
|
77
|
+
* @param filePath - Output file path.
|
|
78
|
+
* @param value - Text content to write.
|
|
79
|
+
*/
|
|
80
|
+
export async function writeText(filePath, value) {
|
|
81
|
+
await ensureDir(path.dirname(filePath));
|
|
82
|
+
await fs.writeFile(filePath, value, "utf8");
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Removes a file or directory recursively when present.
|
|
86
|
+
*
|
|
87
|
+
* @param targetPath - File system path to remove.
|
|
88
|
+
*/
|
|
89
|
+
export async function removePath(targetPath) {
|
|
90
|
+
await fs.rm(targetPath, { recursive: true, force: true });
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Creates a relative symlink and reports whether the caller should fall back to copy mode.
|
|
94
|
+
*
|
|
95
|
+
* @param targetPath - Absolute path the link should point to.
|
|
96
|
+
* @param linkPath - Absolute path of the symlink to create.
|
|
97
|
+
* @returns Symlink creation result.
|
|
98
|
+
*/
|
|
99
|
+
export async function createSymlink(targetPath, linkPath) {
|
|
100
|
+
const relativeTarget = path.relative(path.dirname(linkPath), targetPath) || ".";
|
|
101
|
+
await ensureDir(path.dirname(linkPath));
|
|
102
|
+
await removePath(linkPath);
|
|
103
|
+
try {
|
|
104
|
+
await fs.symlink(relativeTarget, linkPath);
|
|
105
|
+
return {
|
|
106
|
+
ok: true,
|
|
107
|
+
fallback: false,
|
|
108
|
+
relativeTarget,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (error &&
|
|
113
|
+
typeof error === "object" &&
|
|
114
|
+
"code" in error &&
|
|
115
|
+
(error.code === "EPERM" || error.code === "ENOTSUP")) {
|
|
116
|
+
return {
|
|
117
|
+
ok: false,
|
|
118
|
+
fallback: true,
|
|
119
|
+
relativeTarget,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Removes a symlink without following it.
|
|
127
|
+
*
|
|
128
|
+
* @param linkPath - Link path to remove when present.
|
|
129
|
+
*/
|
|
130
|
+
export async function removeSymlink(linkPath) {
|
|
131
|
+
try {
|
|
132
|
+
const stats = await fs.lstat(linkPath);
|
|
133
|
+
if (stats.isSymbolicLink()) {
|
|
134
|
+
await fs.unlink(linkPath);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Reads a symlink target when the path is a symbolic link.
|
|
146
|
+
*
|
|
147
|
+
* @param linkPath - Candidate link path.
|
|
148
|
+
* @returns Link target or `null` when the path is missing or not a symlink.
|
|
149
|
+
*/
|
|
150
|
+
export async function readSymlink(linkPath) {
|
|
151
|
+
try {
|
|
152
|
+
const stats = await fs.lstat(linkPath);
|
|
153
|
+
if (!stats.isSymbolicLink()) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
return await fs.readlink(linkPath);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Validates and normalizes a safe relative path.
|
|
167
|
+
*
|
|
168
|
+
* @param relativePath - Candidate relative path.
|
|
169
|
+
* @returns Normalized POSIX relative path.
|
|
170
|
+
* @throws {ValidationError} When the path is empty, absolute, or escapes the root.
|
|
171
|
+
*/
|
|
172
|
+
export function assertSafeRelativePath(relativePath) {
|
|
173
|
+
if (!relativePath || relativePath.includes("\0")) {
|
|
174
|
+
throw new ValidationError(`Caminho invalido: "${relativePath}"`);
|
|
175
|
+
}
|
|
176
|
+
const normalized = path.posix.normalize(relativePath);
|
|
177
|
+
if (normalized.startsWith("../") ||
|
|
178
|
+
normalized === ".." ||
|
|
179
|
+
path.isAbsolute(relativePath) ||
|
|
180
|
+
normalized.startsWith("/")) {
|
|
181
|
+
throw new ValidationError(`Caminho inseguro detectado: "${relativePath}"`);
|
|
182
|
+
}
|
|
183
|
+
return normalized;
|
|
184
|
+
}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP fetch utilities with GitHub API support.
|
|
3
|
+
*
|
|
4
|
+
* Automatically attaches GitHub headers and, when `GITHUB_TOKEN` is set in
|
|
5
|
+
* the environment, an `Authorization: Bearer` header to raise the API rate
|
|
6
|
+
* limit from 60 to 5,000 requests per hour.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Fetches a JSON document and parses it with default Skillex headers.
|
|
10
|
+
*
|
|
11
|
+
* @param url - Target URL.
|
|
12
|
+
* @param init - Fetch init overrides.
|
|
13
|
+
* @returns Parsed JSON payload.
|
|
14
|
+
* @throws {Error} With an actionable message on HTTP errors.
|
|
15
|
+
*/
|
|
16
|
+
export declare function fetchJson<T>(url: string, init?: RequestInit): Promise<T>;
|
|
17
|
+
/**
|
|
18
|
+
* Fetches a UTF-8 text resource with default Skillex headers.
|
|
19
|
+
*
|
|
20
|
+
* @param url - Target URL.
|
|
21
|
+
* @param init - Fetch init overrides.
|
|
22
|
+
* @returns Response text body.
|
|
23
|
+
* @throws {Error} With an actionable message on HTTP errors.
|
|
24
|
+
*/
|
|
25
|
+
export declare function fetchText(url: string, init?: RequestInit): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Fetches a UTF-8 text resource and returns `null` when the resource does not exist.
|
|
28
|
+
*
|
|
29
|
+
* @param url - Target URL.
|
|
30
|
+
* @param init - Fetch init overrides.
|
|
31
|
+
* @returns Response text body or `null` for HTTP 404.
|
|
32
|
+
* @throws {Error} With an actionable message on non-404 HTTP errors.
|
|
33
|
+
*/
|
|
34
|
+
export declare function fetchOptionalText(url: string, init?: RequestInit): Promise<string | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Fetches a JSON document and returns `null` when the resource does not exist.
|
|
37
|
+
*
|
|
38
|
+
* @param url - Target URL.
|
|
39
|
+
* @param init - Fetch init overrides.
|
|
40
|
+
* @returns Parsed JSON payload or `null` for HTTP 404.
|
|
41
|
+
* @throws {Error} With an actionable message on non-404 HTTP errors.
|
|
42
|
+
*/
|
|
43
|
+
export declare function fetchOptionalJson<T>(url: string, init?: RequestInit): Promise<T | null>;
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP fetch utilities with GitHub API support.
|
|
3
|
+
*
|
|
4
|
+
* Automatically attaches GitHub headers and, when `GITHUB_TOKEN` is set in
|
|
5
|
+
* the environment, an `Authorization: Bearer` header to raise the API rate
|
|
6
|
+
* limit from 60 to 5,000 requests per hour.
|
|
7
|
+
*/
|
|
8
|
+
import { debug } from "./output.js";
|
|
9
|
+
/**
|
|
10
|
+
* Fetches a JSON document and parses it with default Skillex headers.
|
|
11
|
+
*
|
|
12
|
+
* @param url - Target URL.
|
|
13
|
+
* @param init - Fetch init overrides.
|
|
14
|
+
* @returns Parsed JSON payload.
|
|
15
|
+
* @throws {Error} With an actionable message on HTTP errors.
|
|
16
|
+
*/
|
|
17
|
+
export async function fetchJson(url, init = {}) {
|
|
18
|
+
debug(`GET ${url}`);
|
|
19
|
+
const response = await fetch(url, withDefaultHeaders(init));
|
|
20
|
+
debug(`${response.status} ${url}`);
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(buildHttpErrorMessage(url, response.status));
|
|
23
|
+
}
|
|
24
|
+
return (await response.json());
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Fetches a UTF-8 text resource with default Skillex headers.
|
|
28
|
+
*
|
|
29
|
+
* @param url - Target URL.
|
|
30
|
+
* @param init - Fetch init overrides.
|
|
31
|
+
* @returns Response text body.
|
|
32
|
+
* @throws {Error} With an actionable message on HTTP errors.
|
|
33
|
+
*/
|
|
34
|
+
export async function fetchText(url, init = {}) {
|
|
35
|
+
debug(`GET ${url}`);
|
|
36
|
+
const response = await fetch(url, withDefaultHeaders(init));
|
|
37
|
+
debug(`${response.status} ${url}`);
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
throw new Error(buildHttpErrorMessage(url, response.status));
|
|
40
|
+
}
|
|
41
|
+
return response.text();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Fetches a UTF-8 text resource and returns `null` when the resource does not exist.
|
|
45
|
+
*
|
|
46
|
+
* @param url - Target URL.
|
|
47
|
+
* @param init - Fetch init overrides.
|
|
48
|
+
* @returns Response text body or `null` for HTTP 404.
|
|
49
|
+
* @throws {Error} With an actionable message on non-404 HTTP errors.
|
|
50
|
+
*/
|
|
51
|
+
export async function fetchOptionalText(url, init = {}) {
|
|
52
|
+
debug(`GET ${url}`);
|
|
53
|
+
const response = await fetch(url, withDefaultHeaders(init));
|
|
54
|
+
debug(`${response.status} ${url}`);
|
|
55
|
+
if (response.status === 404) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
throw new Error(buildHttpErrorMessage(url, response.status));
|
|
60
|
+
}
|
|
61
|
+
return response.text();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Fetches a JSON document and returns `null` when the resource does not exist.
|
|
65
|
+
*
|
|
66
|
+
* @param url - Target URL.
|
|
67
|
+
* @param init - Fetch init overrides.
|
|
68
|
+
* @returns Parsed JSON payload or `null` for HTTP 404.
|
|
69
|
+
* @throws {Error} With an actionable message on non-404 HTTP errors.
|
|
70
|
+
*/
|
|
71
|
+
export async function fetchOptionalJson(url, init = {}) {
|
|
72
|
+
debug(`GET ${url}`);
|
|
73
|
+
const response = await fetch(url, withDefaultHeaders(init));
|
|
74
|
+
debug(`${response.status} ${url}`);
|
|
75
|
+
if (response.status === 404) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
throw new Error(buildHttpErrorMessage(url, response.status));
|
|
80
|
+
}
|
|
81
|
+
return (await response.json());
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Applies default HTTP headers expected by GitHub-hosted catalog requests.
|
|
85
|
+
* Attaches `Authorization: Bearer` when `GITHUB_TOKEN` is set in the environment.
|
|
86
|
+
*
|
|
87
|
+
* @param init - User-supplied fetch options.
|
|
88
|
+
* @returns Fetch options with default headers merged in.
|
|
89
|
+
*/
|
|
90
|
+
function withDefaultHeaders(init) {
|
|
91
|
+
const headers = new Headers(init.headers || {});
|
|
92
|
+
if (!headers.has("User-Agent")) {
|
|
93
|
+
headers.set("User-Agent", "skillex");
|
|
94
|
+
}
|
|
95
|
+
if (!headers.has("Accept")) {
|
|
96
|
+
headers.set("Accept", "application/vnd.github+json");
|
|
97
|
+
}
|
|
98
|
+
const token = process.env.GITHUB_TOKEN;
|
|
99
|
+
if (token && !headers.has("Authorization")) {
|
|
100
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
101
|
+
debug("Using GITHUB_TOKEN for authentication");
|
|
102
|
+
}
|
|
103
|
+
return { ...init, headers };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Builds a human-readable, actionable error message for HTTP failures.
|
|
107
|
+
*
|
|
108
|
+
* @param url - The URL that failed.
|
|
109
|
+
* @param status - HTTP response status code.
|
|
110
|
+
* @returns Descriptive error message.
|
|
111
|
+
*/
|
|
112
|
+
function buildHttpErrorMessage(url, status) {
|
|
113
|
+
if (status === 403) {
|
|
114
|
+
return "GitHub API rate limit exceeded or access denied. Set the GITHUB_TOKEN environment variable to authenticate.";
|
|
115
|
+
}
|
|
116
|
+
if (status === 404) {
|
|
117
|
+
return `Repository or file not found. Check that --repo is correct and the repository is public. (${url})`;
|
|
118
|
+
}
|
|
119
|
+
if (status >= 500) {
|
|
120
|
+
return `GitHub API returned a server error (${status}). Try again in a moment.`;
|
|
121
|
+
}
|
|
122
|
+
return `Failed to fetch ${url} (HTTP ${status})`;
|
|
123
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { AggregatedCatalogData, CatalogLoader, CatalogSource, DirectGitHubRef, InitProjectResult, InstallSkillsResult, LockfileSource, LockfileState, ProjectOptions, RemoveSkillsResult, SkillDownloader, SyncCommandResult, UpdateInstalledSkillsResult } from "./types.js";
|
|
2
|
+
interface InstallOptions extends ProjectOptions {
|
|
3
|
+
catalogLoader?: CatalogLoader;
|
|
4
|
+
downloader?: SkillDownloader;
|
|
5
|
+
installAll?: boolean;
|
|
6
|
+
confirm?: (() => Promise<boolean>) | undefined;
|
|
7
|
+
warn?: ((message: string) => void) | undefined;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Initializes the local Skillex workspace state.
|
|
11
|
+
*
|
|
12
|
+
* @param options - Project initialization options.
|
|
13
|
+
* @returns Lockfile initialization result.
|
|
14
|
+
* @throws {InstallError} When initialization fails.
|
|
15
|
+
*/
|
|
16
|
+
export declare function initProject(options?: ProjectOptions): Promise<InitProjectResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Installs one or more catalog skills or direct GitHub skills into the local workspace state.
|
|
19
|
+
*
|
|
20
|
+
* @param requestedSkillIds - Requested skill ids or `owner/repo[@ref]` direct references.
|
|
21
|
+
* @param options - Installation options.
|
|
22
|
+
* @returns Install summary.
|
|
23
|
+
* @throws {InstallError} When installation fails.
|
|
24
|
+
*/
|
|
25
|
+
export declare function installSkills(requestedSkillIds: string[], options?: InstallOptions): Promise<InstallSkillsResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Updates installed skills from the configured remote catalog or their direct GitHub sources.
|
|
28
|
+
*
|
|
29
|
+
* @param requestedSkillIds - Optional subset of installed skills to update.
|
|
30
|
+
* @param options - Update options.
|
|
31
|
+
* @returns Update summary.
|
|
32
|
+
* @throws {InstallError} When update fails.
|
|
33
|
+
*/
|
|
34
|
+
export declare function updateInstalledSkills(requestedSkillIds: string[], options?: InstallOptions): Promise<UpdateInstalledSkillsResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Removes installed skills from the local workspace state.
|
|
37
|
+
*
|
|
38
|
+
* @param requestedSkillIds - Skill ids to remove.
|
|
39
|
+
* @param options - Remove options.
|
|
40
|
+
* @returns Remove summary.
|
|
41
|
+
* @throws {InstallError} When removal fails.
|
|
42
|
+
*/
|
|
43
|
+
export declare function removeSkills(requestedSkillIds: string[], options?: ProjectOptions): Promise<RemoveSkillsResult>;
|
|
44
|
+
/**
|
|
45
|
+
* Synchronizes installed skills to the active or requested adapter target.
|
|
46
|
+
*
|
|
47
|
+
* @param options - Sync options.
|
|
48
|
+
* @returns Sync command result.
|
|
49
|
+
* @throws {InstallError} When workspace state is missing or invalid.
|
|
50
|
+
*/
|
|
51
|
+
export declare function syncInstalledSkills(options?: ProjectOptions): Promise<SyncCommandResult>;
|
|
52
|
+
/**
|
|
53
|
+
* Reads the local workspace lockfile when it exists.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Project lookup options.
|
|
56
|
+
* @returns Normalized lockfile state or `null` when no install exists.
|
|
57
|
+
*/
|
|
58
|
+
export declare function getInstalledSkills(options?: ProjectOptions): Promise<LockfileState | null>;
|
|
59
|
+
/**
|
|
60
|
+
* Resolves the effective project catalog source using CLI overrides or local state.
|
|
61
|
+
*
|
|
62
|
+
* @param options - Project lookup options.
|
|
63
|
+
* @returns Resolved catalog source.
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveProjectSource(options?: ProjectOptions): Promise<CatalogSource>;
|
|
66
|
+
/**
|
|
67
|
+
* Resolves all effective project sources using CLI overrides or local state.
|
|
68
|
+
*
|
|
69
|
+
* @param options - Project lookup options.
|
|
70
|
+
* @returns Resolved source list.
|
|
71
|
+
*/
|
|
72
|
+
export declare function resolveProjectSources(options?: ProjectOptions): Promise<LockfileSource[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Aggregates skills from all effective project sources.
|
|
75
|
+
*
|
|
76
|
+
* @param options - Project lookup options.
|
|
77
|
+
* @param catalogLoader - Optional catalog loader override.
|
|
78
|
+
* @returns Aggregated skills grouped by source metadata.
|
|
79
|
+
*/
|
|
80
|
+
export declare function loadProjectCatalogs(options?: ProjectOptions, catalogLoader?: CatalogLoader): Promise<AggregatedCatalogData>;
|
|
81
|
+
/**
|
|
82
|
+
* Adds a source to the workspace lockfile.
|
|
83
|
+
*
|
|
84
|
+
* @param sourceInput - Repository to add.
|
|
85
|
+
* @param options - Project options.
|
|
86
|
+
* @returns Updated normalized lockfile.
|
|
87
|
+
*/
|
|
88
|
+
export declare function addProjectSource(sourceInput: {
|
|
89
|
+
repo: string;
|
|
90
|
+
ref?: string | undefined;
|
|
91
|
+
label?: string | undefined;
|
|
92
|
+
}, options?: ProjectOptions): Promise<LockfileState>;
|
|
93
|
+
/**
|
|
94
|
+
* Removes a source from the workspace lockfile.
|
|
95
|
+
*
|
|
96
|
+
* @param repo - Repository to remove.
|
|
97
|
+
* @param options - Project options.
|
|
98
|
+
* @returns Updated normalized lockfile.
|
|
99
|
+
*/
|
|
100
|
+
export declare function removeProjectSource(repo: string, options?: ProjectOptions): Promise<LockfileState>;
|
|
101
|
+
/**
|
|
102
|
+
* Lists configured workspace sources.
|
|
103
|
+
*
|
|
104
|
+
* @param options - Project options.
|
|
105
|
+
* @returns Normalized source list.
|
|
106
|
+
*/
|
|
107
|
+
export declare function listProjectSources(options?: ProjectOptions): Promise<LockfileSource[]>;
|
|
108
|
+
/**
|
|
109
|
+
* Parses a direct GitHub install reference in `owner/repo[@ref]` format.
|
|
110
|
+
*
|
|
111
|
+
* @param input - User-supplied install argument.
|
|
112
|
+
* @returns Parsed direct GitHub reference or `null` when the value is not a direct ref.
|
|
113
|
+
*/
|
|
114
|
+
export declare function parseDirectGitHubRef(input: string): DirectGitHubRef | null;
|
|
115
|
+
export {};
|