@sstar/skill-install 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.DownloadManager = void 0;
40
+ const fs_1 = require("fs");
41
+ const promises_1 = require("fs/promises");
42
+ const path_1 = __importDefault(require("path"));
43
+ const promises_2 = require("stream/promises");
44
+ const axios_1 = __importDefault(require("axios"));
45
+ const http_client_1 = require("../http/http-client");
46
+ const auth_service_1 = require("../auth/auth-service");
47
+ const logger_1 = require("../core/logger");
48
+ const errors_1 = require("../core/errors");
49
+ /**
50
+ * Download Manager with support for both authenticated (wiki) and public downloads
51
+ */
52
+ class DownloadManager {
53
+ constructor() {
54
+ this.logger = new logger_1.Logger('DownloadManager');
55
+ }
56
+ /**
57
+ * Download a file from a URL
58
+ * If requireAuth is true, use the AuthService for authentication
59
+ */
60
+ async download(options) {
61
+ try {
62
+ // Ensure parent directory exists
63
+ const dir = path_1.default.dirname(options.outputPath);
64
+ await (0, promises_1.mkdir)(dir, { recursive: true });
65
+ this.logger.info(`Downloading: ${options.url} -> ${options.outputPath}`);
66
+ if (options.requireAuth) {
67
+ return await this.downloadWithAuth(options);
68
+ }
69
+ else {
70
+ return await this.downloadDirect(options);
71
+ }
72
+ }
73
+ catch (error) {
74
+ const errorMsg = error instanceof Error ? error.message : String(error);
75
+ this.logger.error(`Download failed: ${errorMsg}`);
76
+ return {
77
+ success: false,
78
+ filepath: options.outputPath,
79
+ size: 0,
80
+ error: errorMsg
81
+ };
82
+ }
83
+ }
84
+ /**
85
+ * Download with authentication (for wiki URLs)
86
+ */
87
+ async downloadWithAuth(options) {
88
+ if (!options.username || !options.password || !options.baseUrl) {
89
+ throw new errors_1.WikiError(errors_1.ErrorType.AUTHENTICATION, 'Username, password, and baseUrl are required for authenticated downloads');
90
+ }
91
+ // Initialize HTTP client and auth service if not already done
92
+ if (!this.http || !this.auth) {
93
+ this.http = new http_client_1.HttpClient({
94
+ baseUrl: options.baseUrl,
95
+ allowSelfSigned: options.allowSelfSigned ?? true,
96
+ timeoutMs: 60000
97
+ });
98
+ this.auth = new auth_service_1.AuthService(this.http, {
99
+ baseUrl: options.baseUrl,
100
+ username: options.username,
101
+ password: options.password
102
+ });
103
+ }
104
+ // Ensure authenticated before downloading
105
+ await this.auth.ensureAuthenticated();
106
+ this.logger.info('Authentication successful, starting download');
107
+ // Perform streaming download
108
+ const response = await this.http.get(options.url, {
109
+ responseType: 'stream'
110
+ });
111
+ // Save file
112
+ const writer = (0, fs_1.createWriteStream)(options.outputPath);
113
+ await (0, promises_2.pipeline)(response.data, writer);
114
+ // Get file size
115
+ const stats = await Promise.resolve().then(() => __importStar(require('fs'))).then(fs => fs.promises.stat(options.outputPath));
116
+ this.logger.info(`Download complete: ${options.outputPath} (${this.formatSize(stats.size)})`);
117
+ return {
118
+ success: true,
119
+ filepath: options.outputPath,
120
+ size: stats.size
121
+ };
122
+ }
123
+ /**
124
+ * Direct download without authentication (for public URLs)
125
+ */
126
+ async downloadDirect(options) {
127
+ const response = await (0, axios_1.default)({
128
+ method: 'GET',
129
+ url: options.url,
130
+ responseType: 'stream',
131
+ timeout: 60000,
132
+ maxRedirects: 5,
133
+ headers: {
134
+ 'User-Agent': 'Skill-Install/1.0.0'
135
+ }
136
+ });
137
+ // Save file
138
+ const writer = (0, fs_1.createWriteStream)(options.outputPath);
139
+ await (0, promises_2.pipeline)(response.data, writer);
140
+ // Get file size
141
+ const stats = await Promise.resolve().then(() => __importStar(require('fs'))).then(fs => fs.promises.stat(options.outputPath));
142
+ this.logger.info(`Download complete: ${options.outputPath} (${this.formatSize(stats.size)})`);
143
+ return {
144
+ success: true,
145
+ filepath: options.outputPath,
146
+ size: stats.size
147
+ };
148
+ }
149
+ formatSize(bytes) {
150
+ if (bytes === 0)
151
+ return '0 B';
152
+ const k = 1024;
153
+ const sizes = ['B', 'KB', 'MB', 'GB'];
154
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
155
+ return `${(bytes / Math.pow(k, i)).toFixed(i === 0 ? 0 : 2)} ${sizes[i]}`;
156
+ }
157
+ /**
158
+ * Extract filename from URL
159
+ */
160
+ extractFilenameFromUrl(url) {
161
+ try {
162
+ const urlObj = new URL(url);
163
+ const pathname = urlObj.pathname;
164
+ const parts = pathname.split('/');
165
+ const lastPart = parts[parts.length - 1];
166
+ // Remove query parameters
167
+ const filename = lastPart.split('?')[0];
168
+ if (filename && filename !== '' && filename !== 'attachments') {
169
+ return decodeURIComponent(filename);
170
+ }
171
+ // Try to find filename in query parameters
172
+ const params = new URLSearchParams(urlObj.search);
173
+ const fileNameParam = params.get('fileName') || params.get('filename');
174
+ if (fileNameParam) {
175
+ return decodeURIComponent(fileNameParam);
176
+ }
177
+ return null;
178
+ }
179
+ catch {
180
+ return null;
181
+ }
182
+ }
183
+ }
184
+ exports.DownloadManager = DownloadManager;
@@ -0,0 +1,29 @@
1
+ export interface DownloadOptions {
2
+ url: string;
3
+ username: string;
4
+ password: string;
5
+ baseUrl: string;
6
+ output?: string;
7
+ allowSelfSigned?: boolean;
8
+ }
9
+ export interface DownloadResult {
10
+ success: boolean;
11
+ filepath: string;
12
+ size: number;
13
+ error?: string;
14
+ }
15
+ export declare class Downloader {
16
+ private readonly logger;
17
+ private readonly http;
18
+ private readonly auth;
19
+ constructor(options: {
20
+ baseUrl: string;
21
+ username: string;
22
+ password: string;
23
+ allowSelfSigned?: boolean;
24
+ });
25
+ download(options: DownloadOptions): Promise<DownloadResult>;
26
+ private extractFilenameFromUrl;
27
+ private pathExists;
28
+ private formatSize;
29
+ }
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.Downloader = void 0;
40
+ const fs_1 = require("fs");
41
+ const promises_1 = require("fs/promises");
42
+ const path_1 = __importDefault(require("path"));
43
+ const promises_2 = require("stream/promises");
44
+ const http_client_1 = require("./http/http-client");
45
+ const auth_service_1 = require("./auth/auth-service");
46
+ const logger_1 = require("./core/logger");
47
+ class Downloader {
48
+ constructor(options) {
49
+ this.logger = new logger_1.Logger('Downloader');
50
+ this.http = new http_client_1.HttpClient({
51
+ baseUrl: options.baseUrl,
52
+ allowSelfSigned: options.allowSelfSigned ?? true,
53
+ timeoutMs: 60000
54
+ });
55
+ this.auth = new auth_service_1.AuthService(this.http, {
56
+ baseUrl: options.baseUrl,
57
+ username: options.username,
58
+ password: options.password
59
+ });
60
+ }
61
+ async download(options) {
62
+ try {
63
+ // Ensure authenticated before downloading
64
+ await this.auth.ensureAuthenticated();
65
+ this.logger.info('Authentication successful, starting download');
66
+ // Determine output path
67
+ let outputPath;
68
+ if (options.output) {
69
+ // If output is a directory, use filename from URL
70
+ const stat = await this.pathExists(options.output);
71
+ if (stat === 'dir') {
72
+ const filename = this.extractFilenameFromUrl(options.url) || 'download';
73
+ outputPath = path_1.default.join(options.output, filename);
74
+ }
75
+ else {
76
+ // Create parent directory if needed
77
+ const dir = path_1.default.dirname(options.output);
78
+ await (0, promises_1.mkdir)(dir, { recursive: true });
79
+ outputPath = options.output;
80
+ }
81
+ }
82
+ else {
83
+ // Use current directory with filename from URL
84
+ const filename = this.extractFilenameFromUrl(options.url) || 'download';
85
+ outputPath = path_1.default.join(process.cwd(), filename);
86
+ }
87
+ // Ensure parent directory exists
88
+ const dir = path_1.default.dirname(outputPath);
89
+ await (0, promises_1.mkdir)(dir, { recursive: true });
90
+ this.logger.info(`Downloading: ${options.url} -> ${outputPath}`);
91
+ // Perform streaming download
92
+ const response = await this.http.get(options.url, {
93
+ responseType: 'stream'
94
+ });
95
+ // Save file
96
+ const writer = (0, fs_1.createWriteStream)(outputPath);
97
+ await (0, promises_2.pipeline)(response.data, writer);
98
+ // Get file size
99
+ const stats = await Promise.resolve().then(() => __importStar(require('fs'))).then(fs => fs.promises.stat(outputPath));
100
+ this.logger.info(`Download complete: ${outputPath} (${this.formatSize(stats.size)})`);
101
+ return {
102
+ success: true,
103
+ filepath: outputPath,
104
+ size: stats.size
105
+ };
106
+ }
107
+ catch (error) {
108
+ const errorMsg = error instanceof Error ? error.message : String(error);
109
+ this.logger.error(`Download failed: ${errorMsg}`);
110
+ return {
111
+ success: false,
112
+ filepath: options.output || options.url,
113
+ size: 0,
114
+ error: errorMsg
115
+ };
116
+ }
117
+ }
118
+ extractFilenameFromUrl(url) {
119
+ try {
120
+ // Parse URL to extract filename
121
+ const urlObj = new URL(url);
122
+ const pathname = urlObj.pathname;
123
+ // Handle typical Confluence attachment URLs
124
+ // e.g., /download/attachments/12345/filename.pdf?api=v2
125
+ const parts = pathname.split('/');
126
+ const lastPart = parts[parts.length - 1];
127
+ // Remove query parameters
128
+ const filename = lastPart.split('?')[0];
129
+ // Handle versioning parameter like filename.pdf?version=1
130
+ if (filename && filename !== '' && filename !== 'attachments') {
131
+ return decodeURIComponent(filename);
132
+ }
133
+ // Try to find filename in query parameters
134
+ const params = new URLSearchParams(urlObj.search);
135
+ const fileNameParam = params.get('fileName') || params.get('filename');
136
+ if (fileNameParam) {
137
+ return decodeURIComponent(fileNameParam);
138
+ }
139
+ return null;
140
+ }
141
+ catch {
142
+ return null;
143
+ }
144
+ }
145
+ async pathExists(p) {
146
+ try {
147
+ const stat = await Promise.resolve().then(() => __importStar(require('fs'))).then(fs => fs.promises.stat(p));
148
+ return stat.isDirectory() ? 'dir' : 'file';
149
+ }
150
+ catch {
151
+ return null;
152
+ }
153
+ }
154
+ formatSize(bytes) {
155
+ if (bytes === 0)
156
+ return '0 B';
157
+ const k = 1024;
158
+ const sizes = ['B', 'KB', 'MB', 'GB'];
159
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
160
+ return `${(bytes / Math.pow(k, i)).toFixed(i === 0 ? 0 : 2)} ${sizes[i]}`;
161
+ }
162
+ }
163
+ exports.Downloader = Downloader;
@@ -0,0 +1,25 @@
1
+ import { AxiosRequestConfig, AxiosResponse } from 'axios';
2
+ export interface HttpClientOptions {
3
+ baseUrl: string;
4
+ allowSelfSigned: boolean;
5
+ timeoutMs?: number;
6
+ }
7
+ export declare class HttpClient {
8
+ private readonly options;
9
+ private readonly client;
10
+ private readonly logger;
11
+ private cookieStore;
12
+ constructor(options: HttpClientOptions);
13
+ private setupInterceptors;
14
+ private extractCookies;
15
+ private normalizeError;
16
+ get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
17
+ post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
18
+ getCookies(): string[];
19
+ setCookies(cookies: string[]): void;
20
+ clearCookies(): void;
21
+ private addCookieHeader;
22
+ setHeader(name: string, value: string): void;
23
+ removeHeader(name: string): void;
24
+ getBaseURL(): string;
25
+ }
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.HttpClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const https_1 = __importDefault(require("https"));
9
+ const logger_1 = require("../core/logger");
10
+ const errors_1 = require("../core/errors");
11
+ class HttpClient {
12
+ constructor(options) {
13
+ this.options = options;
14
+ this.logger = new logger_1.Logger('HttpClient');
15
+ this.cookieStore = new Map();
16
+ // 设置环境变量来忽略证书验证(必须在创建axios实例之前)
17
+ this.logger.info(`HTTP Client config: baseUrl=${options.baseUrl}, allowSelfSigned=${options.allowSelfSigned}`);
18
+ if (options.baseUrl.startsWith('https://') && options.allowSelfSigned) {
19
+ process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
20
+ this.logger.warn('SSL certificate verification disabled for self-signed certificates');
21
+ }
22
+ // 配置axios实例
23
+ const axiosConfig = {
24
+ baseURL: options.baseUrl,
25
+ timeout: options.timeoutMs ?? 30000,
26
+ withCredentials: true,
27
+ maxRedirects: 5,
28
+ validateStatus: (status) => status >= 200 && status < 400,
29
+ headers: {
30
+ 'User-Agent': 'Wiki-Download-Tool/1.0.0',
31
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
32
+ 'Accept-Language': 'en-US,en;q=0.5',
33
+ 'Accept-Encoding': 'gzip, deflate',
34
+ 'Connection': 'keep-alive',
35
+ 'Upgrade-Insecure-Requests': '1'
36
+ }
37
+ };
38
+ // 如果需要支持自签名证书,使用自定义https agent
39
+ if (options.baseUrl.startsWith('https://') && options.allowSelfSigned) {
40
+ axiosConfig.httpsAgent = new https_1.default.Agent({
41
+ rejectUnauthorized: false
42
+ });
43
+ }
44
+ this.client = axios_1.default.create(axiosConfig);
45
+ this.setupInterceptors();
46
+ }
47
+ setupInterceptors() {
48
+ this.client.interceptors.request.use((config) => {
49
+ this.logger.debug(`HTTP ${config.method?.toUpperCase()} ${config.url}`);
50
+ this.addCookieHeader(config);
51
+ return config;
52
+ });
53
+ this.client.interceptors.response.use((response) => {
54
+ this.logger.debug(`HTTP ${response.status} ${response.config.url}`);
55
+ this.extractCookies(response);
56
+ return response;
57
+ }, (error) => {
58
+ throw this.normalizeError(error);
59
+ });
60
+ }
61
+ extractCookies(response) {
62
+ const setCookieHeader = response.headers['set-cookie'];
63
+ if (setCookieHeader) {
64
+ const cookies = Array.isArray(setCookieHeader) ? setCookieHeader : [setCookieHeader];
65
+ cookies.forEach(cookie => {
66
+ const cookieParts = cookie.split(';');
67
+ if (cookieParts.length > 0) {
68
+ const cookiePart = cookieParts[0];
69
+ if (cookiePart) {
70
+ const [name, value] = cookiePart.split('=');
71
+ if (name && value) {
72
+ this.cookieStore.set(name.trim(), `${name.trim()}=${value}`);
73
+ }
74
+ }
75
+ }
76
+ });
77
+ }
78
+ }
79
+ normalizeError(error) {
80
+ this.logger.error('HTTP Error details:', {
81
+ message: error.message,
82
+ code: error.code,
83
+ status: error.response?.status,
84
+ statusText: error.response?.statusText,
85
+ url: error.config?.url,
86
+ responseData: error.response?.data ? String(error.response.data).substring(0, 500) : undefined
87
+ });
88
+ if (error.response) {
89
+ const status = error.response.status;
90
+ const statusText = error.response.statusText;
91
+ switch (status) {
92
+ case 401:
93
+ return new errors_1.WikiError(errors_1.ErrorType.AUTHENTICATION, 'Authentication failed. Please check your credentials.', error);
94
+ case 403:
95
+ return new errors_1.WikiError(errors_1.ErrorType.ACCESS_DENIED, 'Access denied. You may not have permission to access this resource.', error);
96
+ case 404:
97
+ return new errors_1.WikiError(errors_1.ErrorType.NOT_FOUND, 'The requested page or resource was not found.', error);
98
+ default:
99
+ return new errors_1.WikiError(errors_1.ErrorType.NETWORK, `HTTP Error ${status}: ${statusText}`, error);
100
+ }
101
+ }
102
+ else if (error.request) {
103
+ return new errors_1.WikiError(errors_1.ErrorType.NETWORK, 'Network error: Unable to reach the server. Please check your internet connection.', error);
104
+ }
105
+ else {
106
+ return new errors_1.WikiError(errors_1.ErrorType.UNKNOWN, `Request setup error: ${error.message}`, error);
107
+ }
108
+ }
109
+ async get(url, config) {
110
+ try {
111
+ return await this.client.get(url, config);
112
+ }
113
+ catch (error) {
114
+ throw this.normalizeError(error);
115
+ }
116
+ }
117
+ async post(url, data, config) {
118
+ try {
119
+ return await this.client.post(url, data, config);
120
+ }
121
+ catch (error) {
122
+ throw this.normalizeError(error);
123
+ }
124
+ }
125
+ getCookies() {
126
+ try {
127
+ return Array.from(this.cookieStore.values());
128
+ }
129
+ catch (error) {
130
+ this.logger.error('Error getting cookies:', error);
131
+ return [];
132
+ }
133
+ }
134
+ setCookies(cookies) {
135
+ try {
136
+ cookies.forEach(cookie => {
137
+ const [name, value] = cookie.split('=');
138
+ if (name && value) {
139
+ this.cookieStore.set(name.trim(), `${name.trim()}=${value}`);
140
+ }
141
+ });
142
+ }
143
+ catch (error) {
144
+ this.logger.error('Error setting cookies:', error);
145
+ }
146
+ }
147
+ clearCookies() {
148
+ try {
149
+ this.cookieStore.clear();
150
+ }
151
+ catch (error) {
152
+ this.logger.error('Error clearing cookies:', error);
153
+ }
154
+ }
155
+ addCookieHeader(config) {
156
+ const cookies = this.getCookies();
157
+ if (cookies.length > 0) {
158
+ config.headers = config.headers || {};
159
+ config.headers['Cookie'] = cookies.join('; ');
160
+ }
161
+ }
162
+ setHeader(name, value) {
163
+ this.client.defaults.headers.common[name] = value;
164
+ }
165
+ removeHeader(name) {
166
+ delete this.client.defaults.headers.common[name];
167
+ }
168
+ getBaseURL() {
169
+ return this.options.baseUrl;
170
+ }
171
+ }
172
+ exports.HttpClient = HttpClient;
@@ -0,0 +1,5 @@
1
+ export { Downloader, DownloadOptions, DownloadResult } from './downloader';
2
+ export { HttpClient, HttpClientOptions } from './http/http-client';
3
+ export { AuthService, AuthConfig } from './auth/auth-service';
4
+ export { Logger, LogLevelName } from './core/logger';
5
+ export { WikiError, ErrorType } from './core/errors';
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorType = exports.WikiError = exports.Logger = exports.AuthService = exports.HttpClient = exports.Downloader = void 0;
4
+ var downloader_1 = require("./downloader");
5
+ Object.defineProperty(exports, "Downloader", { enumerable: true, get: function () { return downloader_1.Downloader; } });
6
+ var http_client_1 = require("./http/http-client");
7
+ Object.defineProperty(exports, "HttpClient", { enumerable: true, get: function () { return http_client_1.HttpClient; } });
8
+ var auth_service_1 = require("./auth/auth-service");
9
+ Object.defineProperty(exports, "AuthService", { enumerable: true, get: function () { return auth_service_1.AuthService; } });
10
+ var logger_1 = require("./core/logger");
11
+ Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return logger_1.Logger; } });
12
+ var errors_1 = require("./core/errors");
13
+ Object.defineProperty(exports, "WikiError", { enumerable: true, get: function () { return errors_1.WikiError; } });
14
+ Object.defineProperty(exports, "ErrorType", { enumerable: true, get: function () { return errors_1.ErrorType; } });
@@ -0,0 +1,40 @@
1
+ export interface InstallOptions {
2
+ source: string;
3
+ skillsDir?: string;
4
+ username?: string;
5
+ password?: string;
6
+ allowSelfSigned?: boolean;
7
+ force?: boolean;
8
+ }
9
+ export interface InstallResult {
10
+ success: boolean;
11
+ skillName?: string;
12
+ skillPath?: string;
13
+ error?: string;
14
+ }
15
+ export declare class InstallService {
16
+ private readonly logger;
17
+ private readonly sourceDetector;
18
+ private readonly downloadManager;
19
+ private readonly extractor;
20
+ private readonly validator;
21
+ private readonly skillsManager;
22
+ /**
23
+ * Install a skill from a source (URL or local file)
24
+ */
25
+ install(options: InstallOptions): Promise<InstallResult>;
26
+ /**
27
+ * Find the skill directory in the extracted files
28
+ * The archive may contain a single root directory or have SKILL.md at root
29
+ */
30
+ private findSkillDirectory;
31
+ /**
32
+ * Move a directory from one location to another
33
+ * Handles cross-device moves by copying and then deleting
34
+ */
35
+ private moveDirectory;
36
+ /**
37
+ * Recursively copy a directory
38
+ */
39
+ private copyDirectory;
40
+ }