@foxian/esl 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/api-error.d.ts +13 -0
- package/dist/api-error.js +31 -0
- package/dist/bin/esl.d.ts +35 -0
- package/dist/bin/esl.js +1033 -0
- package/dist/builtin/builtin-packages.json +11 -0
- package/dist/builtin/esl-operator/SKILL.md +65 -0
- package/dist/builtin/esl-operator/references/agent-interaction.md +110 -0
- package/dist/builtin/esl-operator/references/author.md +98 -0
- package/dist/builtin/esl-operator/references/consumer.md +109 -0
- package/dist/builtin/esl-operator/references/setup.md +41 -0
- package/dist/builtin/esl-operator/skill.json +7 -0
- package/dist/builtin-dir.d.ts +1 -0
- package/dist/builtin-dir.js +11 -0
- package/dist/commands/adapt.d.ts +8 -0
- package/dist/commands/adapt.js +27 -0
- package/dist/commands/admin.d.ts +11 -0
- package/dist/commands/admin.js +96 -0
- package/dist/commands/clone.d.ts +10 -0
- package/dist/commands/clone.js +21 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.js +19 -0
- package/dist/commands/delete.d.ts +13 -0
- package/dist/commands/delete.js +51 -0
- package/dist/commands/deprecate.d.ts +16 -0
- package/dist/commands/deprecate.js +29 -0
- package/dist/commands/import.d.ts +14 -0
- package/dist/commands/import.js +21 -0
- package/dist/commands/info.d.ts +28 -0
- package/dist/commands/info.js +69 -0
- package/dist/commands/init.d.ts +28 -0
- package/dist/commands/init.js +252 -0
- package/dist/commands/install.d.ts +17 -0
- package/dist/commands/install.js +435 -0
- package/dist/commands/link.d.ts +11 -0
- package/dist/commands/link.js +170 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.js +7 -0
- package/dist/commands/login.d.ts +20 -0
- package/dist/commands/login.js +132 -0
- package/dist/commands/logout.d.ts +6 -0
- package/dist/commands/logout.js +18 -0
- package/dist/commands/network-options.d.ts +27 -0
- package/dist/commands/network-options.js +133 -0
- package/dist/commands/notes.d.ts +10 -0
- package/dist/commands/notes.js +24 -0
- package/dist/commands/publish.d.ts +19 -0
- package/dist/commands/publish.js +271 -0
- package/dist/commands/release-delete.d.ts +21 -0
- package/dist/commands/release-delete.js +34 -0
- package/dist/commands/release-manifest.d.ts +5 -0
- package/dist/commands/release-manifest.js +23 -0
- package/dist/commands/rename.d.ts +5 -0
- package/dist/commands/rename.js +25 -0
- package/dist/commands/repair-tag.d.ts +5 -0
- package/dist/commands/repair-tag.js +14 -0
- package/dist/commands/reset-source.d.ts +16 -0
- package/dist/commands/reset-source.js +71 -0
- package/dist/commands/resolve-unlink-identity.d.ts +14 -0
- package/dist/commands/resolve-unlink-identity.js +47 -0
- package/dist/commands/search.d.ts +19 -0
- package/dist/commands/search.js +33 -0
- package/dist/commands/share.d.ts +17 -0
- package/dist/commands/share.js +56 -0
- package/dist/commands/source.d.ts +10 -0
- package/dist/commands/source.js +34 -0
- package/dist/commands/status.d.ts +16 -0
- package/dist/commands/status.js +77 -0
- package/dist/commands/sync-builtin.d.ts +10 -0
- package/dist/commands/sync-builtin.js +68 -0
- package/dist/commands/tools.d.ts +19 -0
- package/dist/commands/tools.js +73 -0
- package/dist/commands/uninstall.d.ts +19 -0
- package/dist/commands/uninstall.js +75 -0
- package/dist/commands/unlink.d.ts +14 -0
- package/dist/commands/unlink.js +108 -0
- package/dist/commands/update.d.ts +18 -0
- package/dist/commands/update.js +176 -0
- package/dist/commands/upload.d.ts +27 -0
- package/dist/commands/upload.js +446 -0
- package/dist/commands/use.d.ts +9 -0
- package/dist/commands/use.js +51 -0
- package/dist/commands/validate.d.ts +4 -0
- package/dist/commands/validate.js +8 -0
- package/dist/commands/version.d.ts +16 -0
- package/dist/commands/version.js +147 -0
- package/dist/commands/whoami.d.ts +14 -0
- package/dist/commands/whoami.js +54 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +24 -0
- package/dist/output.d.ts +1 -0
- package/dist/output.js +3 -0
- package/dist/postinstall.d.ts +1 -0
- package/dist/postinstall.js +8 -0
- package/dist/prompt.d.ts +9 -0
- package/dist/prompt.js +24 -0
- package/dist/vendor/core/adapt/adapt-engine.d.ts +24 -0
- package/dist/vendor/core/adapt/adapt-engine.js +99 -0
- package/dist/vendor/core/adapt/adapted-skill-copy.d.ts +2 -0
- package/dist/vendor/core/adapt/adapted-skill-copy.js +17 -0
- package/dist/vendor/core/adapt/claude-adapter.d.ts +8 -0
- package/dist/vendor/core/adapt/claude-adapter.js +19 -0
- package/dist/vendor/core/adapt/codex-adapter.d.ts +8 -0
- package/dist/vendor/core/adapt/codex-adapter.js +19 -0
- package/dist/vendor/core/adapt/index.d.ts +2 -0
- package/dist/vendor/core/adapt/index.js +2 -0
- package/dist/vendor/core/adapt/tool-adapter.d.ts +12 -0
- package/dist/vendor/core/adapt/tool-adapter.js +1 -0
- package/dist/vendor/core/adapt/trae-adapter.d.ts +8 -0
- package/dist/vendor/core/adapt/trae-adapter.js +19 -0
- package/dist/vendor/core/adapt/trae-cn-adapter.d.ts +8 -0
- package/dist/vendor/core/adapt/trae-cn-adapter.js +19 -0
- package/dist/vendor/core/agent-interaction.d.ts +58 -0
- package/dist/vendor/core/agent-interaction.js +58 -0
- package/dist/vendor/core/command-params.d.ts +5 -0
- package/dist/vendor/core/command-params.js +46 -0
- package/dist/vendor/core/index.d.ts +22 -0
- package/dist/vendor/core/index.js +22 -0
- package/dist/vendor/core/link/skill-links.d.ts +38 -0
- package/dist/vendor/core/link/skill-links.js +245 -0
- package/dist/vendor/core/link/tool-links.d.ts +83 -0
- package/dist/vendor/core/link/tool-links.js +376 -0
- package/dist/vendor/core/org/account-policy.d.ts +8 -0
- package/dist/vendor/core/org/account-policy.js +57 -0
- package/dist/vendor/core/org/org-name.d.ts +2 -0
- package/dist/vendor/core/org/org-name.js +22 -0
- package/dist/vendor/core/org/standing-teams.d.ts +10 -0
- package/dist/vendor/core/org/standing-teams.js +27 -0
- package/dist/vendor/core/schema/compatibility.d.ts +17 -0
- package/dist/vendor/core/schema/compatibility.js +45 -0
- package/dist/vendor/core/schema/release-manifest.d.ts +88 -0
- package/dist/vendor/core/schema/release-manifest.js +161 -0
- package/dist/vendor/core/schema/skill-json.d.ts +61 -0
- package/dist/vendor/core/schema/skill-json.js +47 -0
- package/dist/vendor/core/schema/validation-result.d.ts +7 -0
- package/dist/vendor/core/schema/validation-result.js +1 -0
- package/dist/vendor/core/skill/builtin-package.d.ts +32 -0
- package/dist/vendor/core/skill/builtin-package.js +143 -0
- package/dist/vendor/core/skill/directory-validator.d.ts +9 -0
- package/dist/vendor/core/skill/directory-validator.js +72 -0
- package/dist/vendor/core/skill/import-skill.d.ts +10 -0
- package/dist/vendor/core/skill/import-skill.js +68 -0
- package/dist/vendor/core/skill/published-package.d.ts +1 -0
- package/dist/vendor/core/skill/published-package.js +9 -0
- package/dist/vendor/core/skill/skill-md.d.ts +15 -0
- package/dist/vendor/core/skill/skill-md.js +32 -0
- package/dist/vendor/core/store/file-copy.d.ts +3 -0
- package/dist/vendor/core/store/file-copy.js +102 -0
- package/dist/vendor/core/store/local-store.d.ts +43 -0
- package/dist/vendor/core/store/local-store.js +104 -0
- package/dist/vendor/core/store/skill-store.d.ts +24 -0
- package/dist/vendor/core/store/skill-store.js +41 -0
- package/dist/vendor/core/store/skills-json.d.ts +34 -0
- package/dist/vendor/core/store/skills-json.js +146 -0
- package/dist/vendor/core/version/select-version.d.ts +16 -0
- package/dist/vendor/core/version/select-version.js +34 -0
- package/dist/vendor/core/version/version.d.ts +2 -0
- package/dist/vendor/core/version/version.js +25 -0
- package/dist/vendor/i18n/api-errors.d.ts +121 -0
- package/dist/vendor/i18n/api-errors.js +240 -0
- package/dist/vendor/i18n/i18n-runtime.d.ts +4 -0
- package/dist/vendor/i18n/i18n-runtime.js +16 -0
- package/dist/vendor/i18n/index.d.ts +5 -0
- package/dist/vendor/i18n/index.js +5 -0
- package/dist/vendor/i18n/locales.d.ts +9 -0
- package/dist/vendor/i18n/locales.js +33 -0
- package/dist/vendor/i18n/resources.d.ts +11 -0
- package/dist/vendor/i18n/resources.js +925 -0
- package/dist/vendor/i18n/translate-api-error.d.ts +8 -0
- package/dist/vendor/i18n/translate-api-error.js +12 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +24 -0
- package/package.json +46 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import { requireOkResponse } from '../api-error.js';
|
|
3
|
+
import { isInteractive, readHidden } from '../prompt.js';
|
|
4
|
+
import { apiUrl, fetchWithTimeout, requireConfigured, requireFreshToken, resolveNetworkConfig } from './network-options.js';
|
|
5
|
+
export async function executeChangeOwnPassword(options) {
|
|
6
|
+
const fetchImpl = options.customFetch ?? fetch;
|
|
7
|
+
const { server, token } = await resolveAdminAuth(options);
|
|
8
|
+
const currentPassword = await resolveCurrentPassword(options);
|
|
9
|
+
const newPassword = await resolveNewPassword(options);
|
|
10
|
+
const res = await fetchWithTimeout(fetchImpl, apiUrl(server, '/api/auth/password'), {
|
|
11
|
+
method: 'POST',
|
|
12
|
+
headers: {
|
|
13
|
+
Authorization: `token ${token}`,
|
|
14
|
+
'Content-Type': 'application/json'
|
|
15
|
+
},
|
|
16
|
+
body: JSON.stringify({ oldPassword: currentPassword, newPassword })
|
|
17
|
+
});
|
|
18
|
+
if (!res.ok) {
|
|
19
|
+
await requireOkResponse(res, 'Failed to change password');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function resolveNewPassword(options) {
|
|
23
|
+
if (options.passwordFile) {
|
|
24
|
+
const password = (await fs.readFile(options.passwordFile, 'utf8')).trim();
|
|
25
|
+
if (!password) {
|
|
26
|
+
throw new Error(`Password file ${options.passwordFile} is empty`);
|
|
27
|
+
}
|
|
28
|
+
return password;
|
|
29
|
+
}
|
|
30
|
+
if (options.noInput) {
|
|
31
|
+
if (options.readInput) {
|
|
32
|
+
return readPasswordFromInput(options.readInput);
|
|
33
|
+
}
|
|
34
|
+
throw new Error('A new password is required; pass --password-file or pipe a password on stdin when using --no-input');
|
|
35
|
+
}
|
|
36
|
+
if (options.readInput) {
|
|
37
|
+
return readPasswordFromInput(options.readInput);
|
|
38
|
+
}
|
|
39
|
+
if (options.readPassword) {
|
|
40
|
+
return readConfirmedPassword(options.readPassword);
|
|
41
|
+
}
|
|
42
|
+
if (!isInteractive()) {
|
|
43
|
+
throw new Error('A new password is required; run interactively, pass --password-file, or pipe a password on stdin');
|
|
44
|
+
}
|
|
45
|
+
return readConfirmedPassword((prompt) => readHidden(prompt));
|
|
46
|
+
}
|
|
47
|
+
async function readPasswordFromInput(readInput) {
|
|
48
|
+
const password = (await readInput()).trim();
|
|
49
|
+
if (!password) {
|
|
50
|
+
throw new Error('Password is required');
|
|
51
|
+
}
|
|
52
|
+
return password;
|
|
53
|
+
}
|
|
54
|
+
async function resolveCurrentPassword(options) {
|
|
55
|
+
if (options.currentPasswordFile) {
|
|
56
|
+
const password = (await fs.readFile(options.currentPasswordFile, 'utf8')).trim();
|
|
57
|
+
if (!password) {
|
|
58
|
+
throw new Error(`Password file ${options.currentPasswordFile} is empty`);
|
|
59
|
+
}
|
|
60
|
+
return password;
|
|
61
|
+
}
|
|
62
|
+
if (options.noInput) {
|
|
63
|
+
if (options.readInput) {
|
|
64
|
+
return readPasswordFromInput(options.readInput);
|
|
65
|
+
}
|
|
66
|
+
throw new Error('A current password is required; pass --current-password-file or pipe a password on stdin when using --no-input');
|
|
67
|
+
}
|
|
68
|
+
if (options.readInput) {
|
|
69
|
+
return readPasswordFromInput(options.readInput);
|
|
70
|
+
}
|
|
71
|
+
if (options.readPassword) {
|
|
72
|
+
return (await options.readPassword('Current password: ')).trim();
|
|
73
|
+
}
|
|
74
|
+
if (!isInteractive()) {
|
|
75
|
+
throw new Error('A current password is required; run interactively or pass --current-password-file');
|
|
76
|
+
}
|
|
77
|
+
return (await readHidden('Current password: ')).trim();
|
|
78
|
+
}
|
|
79
|
+
async function readConfirmedPassword(readPassword) {
|
|
80
|
+
const password = (await readPassword('New password: ')).trim();
|
|
81
|
+
if (!password) {
|
|
82
|
+
throw new Error('Password is required');
|
|
83
|
+
}
|
|
84
|
+
const confirmPassword = (await readPassword('Confirm new password: ')).trim();
|
|
85
|
+
if (password !== confirmPassword) {
|
|
86
|
+
throw new Error('Passwords do not match');
|
|
87
|
+
}
|
|
88
|
+
return password;
|
|
89
|
+
}
|
|
90
|
+
async function resolveAdminAuth(options) {
|
|
91
|
+
const config = await resolveNetworkConfig(options);
|
|
92
|
+
return {
|
|
93
|
+
server: config.server,
|
|
94
|
+
token: requireConfigured(await requireFreshToken(options), 'token')
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { type NetworkCommandOptions } from './network-options.js';
|
|
3
|
+
declare const defaultExecFileAsync: typeof execFile.__promisify__;
|
|
4
|
+
export interface CloneOptions extends NetworkCommandOptions {
|
|
5
|
+
target?: string;
|
|
6
|
+
cwd?: string;
|
|
7
|
+
execFileAsync?: typeof defaultExecFileAsync;
|
|
8
|
+
}
|
|
9
|
+
export declare function executeClone(name: string, options?: CloneOptions): Promise<string>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import { parseSkillName } from '../vendor/core/index.js';
|
|
5
|
+
import { authenticatedGitUrl, requireConfigured, resolveNetworkConfig } from './network-options.js';
|
|
6
|
+
import { executeInfo } from './info.js';
|
|
7
|
+
const defaultExecFileAsync = promisify(execFile);
|
|
8
|
+
export async function executeClone(name, options = {}) {
|
|
9
|
+
const execFileAsync = options.execFileAsync ?? defaultExecFileAsync;
|
|
10
|
+
const { gitBase, token } = await resolveNetworkConfig(options);
|
|
11
|
+
const gitHttpBase = requireConfigured(gitBase, 'git-base');
|
|
12
|
+
const authToken = requireConfigured(token, 'token');
|
|
13
|
+
const info = await executeInfo(name, options);
|
|
14
|
+
const repoPath = requireConfigured(info.gitRepoPath, 'gitRepoPath');
|
|
15
|
+
const remoteUrl = authenticatedGitUrl(gitHttpBase, authToken, repoPath);
|
|
16
|
+
const { skillName } = parseSkillName(name);
|
|
17
|
+
const cwd = options.cwd ?? process.cwd();
|
|
18
|
+
const targetDir = options.target ?? path.join(cwd, skillName);
|
|
19
|
+
await execFileAsync('git', ['clone', remoteUrl, targetDir]);
|
|
20
|
+
return targetDir;
|
|
21
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type LocalStoreOptions } from '@esl/core';
|
|
2
|
+
export interface ConfigCommandOptions extends LocalStoreOptions {
|
|
3
|
+
server?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function executeSetServer(url: string, options?: LocalStoreOptions): Promise<{
|
|
6
|
+
server: string;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function resolveServer(options?: ConfigCommandOptions): Promise<string>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { loadConfig, saveConfig } from '../vendor/core/index.js';
|
|
2
|
+
export async function executeSetServer(url, options = {}) {
|
|
3
|
+
const config = await saveConfig({ server: url }, { homeDir: options.homeDir });
|
|
4
|
+
return { server: config.server };
|
|
5
|
+
}
|
|
6
|
+
export async function resolveServer(options = {}) {
|
|
7
|
+
if (options.server) {
|
|
8
|
+
return options.server;
|
|
9
|
+
}
|
|
10
|
+
const fromEnv = process.env.ESL_SERVER;
|
|
11
|
+
if (fromEnv) {
|
|
12
|
+
return fromEnv;
|
|
13
|
+
}
|
|
14
|
+
const config = await loadConfig({ homeDir: options.homeDir });
|
|
15
|
+
if (!config.server) {
|
|
16
|
+
throw new Error('Missing server; run esl config set-server <url> or pass --server');
|
|
17
|
+
}
|
|
18
|
+
return config.server;
|
|
19
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type NetworkCommandOptions } from './network-options.js';
|
|
2
|
+
export interface DeleteOptions extends NetworkCommandOptions {
|
|
3
|
+
yes?: boolean;
|
|
4
|
+
noInput?: boolean;
|
|
5
|
+
confirmInput?: () => Promise<boolean>;
|
|
6
|
+
}
|
|
7
|
+
export interface DeletedSkill {
|
|
8
|
+
deleted: boolean;
|
|
9
|
+
name: string;
|
|
10
|
+
skillId?: string;
|
|
11
|
+
releasesRemoved?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function executeDelete(identity: string, options: DeleteOptions): Promise<DeletedSkill>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { parseSkillName, isBuiltinIdentity } from '../vendor/core/index.js';
|
|
2
|
+
import { apiUrl, fetchWithTimeout, requireFreshToken, resolveNetworkConfig } from './network-options.js';
|
|
3
|
+
import { confirm, isInteractive, readText } from '../prompt.js';
|
|
4
|
+
export async function executeDelete(identity, options) {
|
|
5
|
+
if (isBuiltinIdentity(identity)) {
|
|
6
|
+
throw new Error(`Unknown built-in skill: ${identity}; built-in skills cannot be deleted`);
|
|
7
|
+
}
|
|
8
|
+
await confirmDelete(identity, options);
|
|
9
|
+
const token = await requireFreshToken(options);
|
|
10
|
+
const server = options.server ?? (await resolveNetworkConfig(options)).server;
|
|
11
|
+
const { scope, skillName } = parseSkillName(identity);
|
|
12
|
+
const fetchImpl = options.customFetch ?? fetch;
|
|
13
|
+
const response = await fetchWithTimeout(fetchImpl, apiUrl(server, `/api/skills/${encodeURIComponent(scope)}/${encodeURIComponent(skillName)}/delete`), {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: {
|
|
16
|
+
Authorization: `token ${token}`,
|
|
17
|
+
'Content-Type': 'application/json'
|
|
18
|
+
},
|
|
19
|
+
body: JSON.stringify({ confirm: identity })
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`Failed to delete skill: ${await response.text()}`);
|
|
23
|
+
}
|
|
24
|
+
return response.json();
|
|
25
|
+
}
|
|
26
|
+
async function confirmDelete(identity, options) {
|
|
27
|
+
if (options.yes) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (options.noInput) {
|
|
31
|
+
throw new Error('Deleting a skill requires confirmation; pass --yes to skip it');
|
|
32
|
+
}
|
|
33
|
+
const confirmFn = options.confirmInput ??
|
|
34
|
+
(async () => {
|
|
35
|
+
if (!isInteractive()) {
|
|
36
|
+
throw new Error('Deleting a skill requires confirmation in an interactive terminal; pass --yes to skip');
|
|
37
|
+
}
|
|
38
|
+
// Double confirmation: an explicit yes, then retyping the full identity so
|
|
39
|
+
// accidental deletion cannot be triggered by a stray "y".
|
|
40
|
+
const first = await confirm(`Permanently delete ${identity}? This cannot be undone. [y/N] `);
|
|
41
|
+
if (!first) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const typed = (await readText(`Type "${identity}" to confirm deletion: `)).trim();
|
|
45
|
+
return typed === identity;
|
|
46
|
+
});
|
|
47
|
+
const confirmed = await confirmFn();
|
|
48
|
+
if (!confirmed) {
|
|
49
|
+
throw new Error('Delete cancelled');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type NetworkCommandOptions } from './network-options.js';
|
|
2
|
+
export interface DeprecateOptions extends NetworkCommandOptions {
|
|
3
|
+
/** The warning shown to anyone installing this release; an empty message clears the mark. */
|
|
4
|
+
message?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DeprecatedRelease {
|
|
7
|
+
skillName: string;
|
|
8
|
+
version: string;
|
|
9
|
+
deprecatedMessage?: string | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Mark a published Skill Release as deprecated (npm deprecate's counterpart), or
|
|
13
|
+
* clear the mark with an empty message. The release stays installable — it just
|
|
14
|
+
* carries a warning.
|
|
15
|
+
*/
|
|
16
|
+
export declare function executeDeprecate(identity: string, version: string, options?: DeprecateOptions): Promise<DeprecatedRelease>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { isBuiltinIdentity, parseSkillName } from '../vendor/core/index.js';
|
|
2
|
+
import { requireOkResponse } from '../api-error.js';
|
|
3
|
+
import { apiUrl, fetchWithTimeout, requireFreshToken, resolveNetworkConfig } from './network-options.js';
|
|
4
|
+
/**
|
|
5
|
+
* Mark a published Skill Release as deprecated (npm deprecate's counterpart), or
|
|
6
|
+
* clear the mark with an empty message. The release stays installable — it just
|
|
7
|
+
* carries a warning.
|
|
8
|
+
*/
|
|
9
|
+
export async function executeDeprecate(identity, version, options = {}) {
|
|
10
|
+
if (isBuiltinIdentity(identity)) {
|
|
11
|
+
throw new Error(`Unknown built-in skill: ${identity}; built-in skills have no releases`);
|
|
12
|
+
}
|
|
13
|
+
const token = await requireFreshToken(options);
|
|
14
|
+
const server = options.server ?? (await resolveNetworkConfig(options)).server;
|
|
15
|
+
const { scope, skillName } = parseSkillName(identity);
|
|
16
|
+
const fetchImpl = options.customFetch ?? fetch;
|
|
17
|
+
const response = await fetchWithTimeout(fetchImpl, apiUrl(server, `/api/skills/${encodeURIComponent(scope)}/${encodeURIComponent(skillName)}/releases/${encodeURIComponent(version)}/deprecate`), {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: {
|
|
20
|
+
Authorization: `token ${token}`,
|
|
21
|
+
'Content-Type': 'application/json'
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({ message: options.message ?? '' })
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
await requireOkResponse(response, 'Failed to update the release deprecation');
|
|
27
|
+
}
|
|
28
|
+
return response.json();
|
|
29
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ImportOptions {
|
|
2
|
+
namespace?: string;
|
|
3
|
+
noAdapt?: boolean;
|
|
4
|
+
projectRoot?: string;
|
|
5
|
+
homeDir?: string;
|
|
6
|
+
author?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ImportResult {
|
|
9
|
+
skillName: string;
|
|
10
|
+
sourceDir: string;
|
|
11
|
+
targetDir: string;
|
|
12
|
+
createdSkillJson: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function executeImport(sourcePath: string, options?: ImportOptions): Promise<ImportResult>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { prepareSkillImport } from '../vendor/core/index.js';
|
|
3
|
+
import { executeInstall } from './install.js';
|
|
4
|
+
export async function executeImport(sourcePath, options = {}) {
|
|
5
|
+
const sourceDir = path.resolve(sourcePath);
|
|
6
|
+
const prepared = await prepareSkillImport(sourceDir, {
|
|
7
|
+
namespace: options.namespace,
|
|
8
|
+
author: options.author
|
|
9
|
+
});
|
|
10
|
+
const targetDir = await executeInstall(prepared.directory, {
|
|
11
|
+
projectRoot: options.projectRoot,
|
|
12
|
+
homeDir: options.homeDir,
|
|
13
|
+
noAdapt: options.noAdapt
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
skillName: prepared.skillName,
|
|
17
|
+
sourceDir: prepared.directory,
|
|
18
|
+
targetDir,
|
|
19
|
+
createdSkillJson: prepared.createdSkillJson
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type NetworkCommandOptions } from './network-options.js';
|
|
2
|
+
export interface SkillInfo {
|
|
3
|
+
name: string;
|
|
4
|
+
/** 对外当前显示名(ADR-0048):曾发布取最近 Release 快照,否则取 upload 同步值。 */
|
|
5
|
+
displayName?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
createdBy?: string;
|
|
8
|
+
owner?: string;
|
|
9
|
+
maintainers?: string[];
|
|
10
|
+
versions?: string[];
|
|
11
|
+
gitRepoPath?: string;
|
|
12
|
+
cloneUrl?: string;
|
|
13
|
+
publishedPackage?: boolean;
|
|
14
|
+
skillId?: string;
|
|
15
|
+
status?: string;
|
|
16
|
+
packageUrl?: string;
|
|
17
|
+
releases?: Array<{
|
|
18
|
+
version: string;
|
|
19
|
+
checksum: string;
|
|
20
|
+
packageUrl?: string;
|
|
21
|
+
/** Present when the release is deprecated: the warning shown on install. */
|
|
22
|
+
deprecatedMessage?: string | null;
|
|
23
|
+
}>;
|
|
24
|
+
currentName?: string;
|
|
25
|
+
oldName?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function executeInfo(name: string, options?: NetworkCommandOptions): Promise<SkillInfo>;
|
|
28
|
+
export declare function formatSkillInfo(info: SkillInfo): string;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { apiUrl, fetchWithTimeout, resolveOptionalFreshToken, withAuthGuidanceIfForbidden, resolveNetworkConfig } from './network-options.js';
|
|
4
|
+
import { isBuiltinIdentity, loadBuiltinPackageOrThrow, sortVersionsDescending } from '../vendor/core/index.js';
|
|
5
|
+
import { resolveBuiltinDir } from '../builtin-dir.js';
|
|
6
|
+
import { ApiError } from '../api-error.js';
|
|
7
|
+
export async function executeInfo(name, options = {}) {
|
|
8
|
+
if (isBuiltinIdentity(name)) {
|
|
9
|
+
return infoFromBuiltin(name, options);
|
|
10
|
+
}
|
|
11
|
+
const fetchImpl = options.customFetch ?? fetch;
|
|
12
|
+
const server = options.server ?? (await resolveNetworkConfig(options)).server;
|
|
13
|
+
// 存在有效登录态时随请求携带 Skill User Token,private 技能对其维护账号可见;
|
|
14
|
+
// public 技能匿名也能访问。
|
|
15
|
+
const token = await resolveOptionalFreshToken({ homeDir: options.homeDir });
|
|
16
|
+
const res = await fetchWithTimeout(fetchImpl, apiUrl(server, `/api/skills/${encodeURIComponent(name)}`), { headers: token ? { Authorization: `token ${token}` } : {} });
|
|
17
|
+
if (!res.ok && res.status !== 301) {
|
|
18
|
+
const err = await res.text();
|
|
19
|
+
const message = `Failed to fetch skill info: ${err}`;
|
|
20
|
+
try {
|
|
21
|
+
const apiError = new ApiError(res.status, message, JSON.parse(err));
|
|
22
|
+
apiError.message = withAuthGuidanceIfForbidden(res.status, message);
|
|
23
|
+
throw apiError;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof ApiError) {
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
throw new Error(withAuthGuidanceIfForbidden(res.status, message));
|
|
31
|
+
}
|
|
32
|
+
const info = (await res.json());
|
|
33
|
+
if (res.status !== 301 || !info.currentName) {
|
|
34
|
+
return info;
|
|
35
|
+
}
|
|
36
|
+
const current = await executeInfo(info.currentName, options);
|
|
37
|
+
return {
|
|
38
|
+
...current,
|
|
39
|
+
oldName: name,
|
|
40
|
+
currentName: info.currentName
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async function infoFromBuiltin(name, options) {
|
|
44
|
+
const builtinDir = options.builtinDir ?? resolveBuiltinDir();
|
|
45
|
+
const builtin = await loadBuiltinPackageOrThrow(builtinDir, name);
|
|
46
|
+
const skillJson = JSON.parse(await fs.readFile(path.join(builtin.directory, 'skill.json'), 'utf8'));
|
|
47
|
+
return {
|
|
48
|
+
name,
|
|
49
|
+
description: skillJson.description,
|
|
50
|
+
versions: [builtin.version]
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function formatSkillInfo(info) {
|
|
54
|
+
const lines = [
|
|
55
|
+
info.displayName && info.displayName !== info.name
|
|
56
|
+
? `Name: ${info.displayName} (${info.name})`
|
|
57
|
+
: `Name: ${info.name}`
|
|
58
|
+
];
|
|
59
|
+
if (info.description) {
|
|
60
|
+
lines.push(`Description: ${info.description}`);
|
|
61
|
+
}
|
|
62
|
+
if (info.versions && info.versions.length > 0) {
|
|
63
|
+
lines.push(`Versions: ${sortVersionsDescending(info.versions).join(', ')}`);
|
|
64
|
+
}
|
|
65
|
+
if (info.gitRepoPath) {
|
|
66
|
+
lines.push(`Repository: ${info.gitRepoPath}`);
|
|
67
|
+
}
|
|
68
|
+
return lines.join('\n');
|
|
69
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type LocalStoreOptions, type ToolName } from '@esl/core';
|
|
2
|
+
export interface InitOptions extends LocalStoreOptions {
|
|
3
|
+
/** Skill directory to fill in (created when missing). Defaults to the current directory. */
|
|
4
|
+
directory?: string;
|
|
5
|
+
/** Skill short name for a generated SKILL.md. Defaults to the directory basename. */
|
|
6
|
+
name?: string;
|
|
7
|
+
/** Namespace for release.json: "personal" (default) or an organization name. */
|
|
8
|
+
namespace?: string;
|
|
9
|
+
runGitInit?: boolean;
|
|
10
|
+
license?: string;
|
|
11
|
+
keywords?: string[];
|
|
12
|
+
description?: string;
|
|
13
|
+
/** release.json displayName;默认按短名 Title Case 生成种子(ADR-0048)。 */
|
|
14
|
+
displayName?: string;
|
|
15
|
+
/** Skips every prompt and writes the missing artifacts as-is. */
|
|
16
|
+
noInput?: boolean;
|
|
17
|
+
/** Injected by tests in place of the interactive prompt. */
|
|
18
|
+
promptText?: (question: string, fallback: string) => Promise<string>;
|
|
19
|
+
/** Injected by tests in place of the real fetch for the namespace menu. */
|
|
20
|
+
customFetch?: typeof fetch;
|
|
21
|
+
/** Emits a structured interaction request instead of reading from the terminal. */
|
|
22
|
+
agentInteraction?: boolean;
|
|
23
|
+
/** AI 工具标识(来自 --agent-tool),用于在交互请求中给出宿主专属提示。 */
|
|
24
|
+
agentTool?: ToolName;
|
|
25
|
+
/** Injected by tests that need a stable interaction request identifier. */
|
|
26
|
+
interactionRequestId?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function executeInit(options?: InitOptions): Promise<string>;
|