@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.
Files changed (173) hide show
  1. package/LICENSE +21 -0
  2. package/dist/api-error.d.ts +13 -0
  3. package/dist/api-error.js +31 -0
  4. package/dist/bin/esl.d.ts +35 -0
  5. package/dist/bin/esl.js +1033 -0
  6. package/dist/builtin/builtin-packages.json +11 -0
  7. package/dist/builtin/esl-operator/SKILL.md +65 -0
  8. package/dist/builtin/esl-operator/references/agent-interaction.md +110 -0
  9. package/dist/builtin/esl-operator/references/author.md +98 -0
  10. package/dist/builtin/esl-operator/references/consumer.md +109 -0
  11. package/dist/builtin/esl-operator/references/setup.md +41 -0
  12. package/dist/builtin/esl-operator/skill.json +7 -0
  13. package/dist/builtin-dir.d.ts +1 -0
  14. package/dist/builtin-dir.js +11 -0
  15. package/dist/commands/adapt.d.ts +8 -0
  16. package/dist/commands/adapt.js +27 -0
  17. package/dist/commands/admin.d.ts +11 -0
  18. package/dist/commands/admin.js +96 -0
  19. package/dist/commands/clone.d.ts +10 -0
  20. package/dist/commands/clone.js +21 -0
  21. package/dist/commands/config.d.ts +8 -0
  22. package/dist/commands/config.js +19 -0
  23. package/dist/commands/delete.d.ts +13 -0
  24. package/dist/commands/delete.js +51 -0
  25. package/dist/commands/deprecate.d.ts +16 -0
  26. package/dist/commands/deprecate.js +29 -0
  27. package/dist/commands/import.d.ts +14 -0
  28. package/dist/commands/import.js +21 -0
  29. package/dist/commands/info.d.ts +28 -0
  30. package/dist/commands/info.js +69 -0
  31. package/dist/commands/init.d.ts +28 -0
  32. package/dist/commands/init.js +252 -0
  33. package/dist/commands/install.d.ts +17 -0
  34. package/dist/commands/install.js +435 -0
  35. package/dist/commands/link.d.ts +11 -0
  36. package/dist/commands/link.js +170 -0
  37. package/dist/commands/list.d.ts +6 -0
  38. package/dist/commands/list.js +7 -0
  39. package/dist/commands/login.d.ts +20 -0
  40. package/dist/commands/login.js +132 -0
  41. package/dist/commands/logout.d.ts +6 -0
  42. package/dist/commands/logout.js +18 -0
  43. package/dist/commands/network-options.d.ts +27 -0
  44. package/dist/commands/network-options.js +133 -0
  45. package/dist/commands/notes.d.ts +10 -0
  46. package/dist/commands/notes.js +24 -0
  47. package/dist/commands/publish.d.ts +19 -0
  48. package/dist/commands/publish.js +271 -0
  49. package/dist/commands/release-delete.d.ts +21 -0
  50. package/dist/commands/release-delete.js +34 -0
  51. package/dist/commands/release-manifest.d.ts +5 -0
  52. package/dist/commands/release-manifest.js +23 -0
  53. package/dist/commands/rename.d.ts +5 -0
  54. package/dist/commands/rename.js +25 -0
  55. package/dist/commands/repair-tag.d.ts +5 -0
  56. package/dist/commands/repair-tag.js +14 -0
  57. package/dist/commands/reset-source.d.ts +16 -0
  58. package/dist/commands/reset-source.js +71 -0
  59. package/dist/commands/resolve-unlink-identity.d.ts +14 -0
  60. package/dist/commands/resolve-unlink-identity.js +47 -0
  61. package/dist/commands/search.d.ts +19 -0
  62. package/dist/commands/search.js +33 -0
  63. package/dist/commands/share.d.ts +17 -0
  64. package/dist/commands/share.js +56 -0
  65. package/dist/commands/source.d.ts +10 -0
  66. package/dist/commands/source.js +34 -0
  67. package/dist/commands/status.d.ts +16 -0
  68. package/dist/commands/status.js +77 -0
  69. package/dist/commands/sync-builtin.d.ts +10 -0
  70. package/dist/commands/sync-builtin.js +68 -0
  71. package/dist/commands/tools.d.ts +19 -0
  72. package/dist/commands/tools.js +73 -0
  73. package/dist/commands/uninstall.d.ts +19 -0
  74. package/dist/commands/uninstall.js +75 -0
  75. package/dist/commands/unlink.d.ts +14 -0
  76. package/dist/commands/unlink.js +108 -0
  77. package/dist/commands/update.d.ts +18 -0
  78. package/dist/commands/update.js +176 -0
  79. package/dist/commands/upload.d.ts +27 -0
  80. package/dist/commands/upload.js +446 -0
  81. package/dist/commands/use.d.ts +9 -0
  82. package/dist/commands/use.js +51 -0
  83. package/dist/commands/validate.d.ts +4 -0
  84. package/dist/commands/validate.js +8 -0
  85. package/dist/commands/version.d.ts +16 -0
  86. package/dist/commands/version.js +147 -0
  87. package/dist/commands/whoami.d.ts +14 -0
  88. package/dist/commands/whoami.js +54 -0
  89. package/dist/index.d.ts +24 -0
  90. package/dist/index.js +24 -0
  91. package/dist/output.d.ts +1 -0
  92. package/dist/output.js +3 -0
  93. package/dist/postinstall.d.ts +1 -0
  94. package/dist/postinstall.js +8 -0
  95. package/dist/prompt.d.ts +9 -0
  96. package/dist/prompt.js +24 -0
  97. package/dist/vendor/core/adapt/adapt-engine.d.ts +24 -0
  98. package/dist/vendor/core/adapt/adapt-engine.js +99 -0
  99. package/dist/vendor/core/adapt/adapted-skill-copy.d.ts +2 -0
  100. package/dist/vendor/core/adapt/adapted-skill-copy.js +17 -0
  101. package/dist/vendor/core/adapt/claude-adapter.d.ts +8 -0
  102. package/dist/vendor/core/adapt/claude-adapter.js +19 -0
  103. package/dist/vendor/core/adapt/codex-adapter.d.ts +8 -0
  104. package/dist/vendor/core/adapt/codex-adapter.js +19 -0
  105. package/dist/vendor/core/adapt/index.d.ts +2 -0
  106. package/dist/vendor/core/adapt/index.js +2 -0
  107. package/dist/vendor/core/adapt/tool-adapter.d.ts +12 -0
  108. package/dist/vendor/core/adapt/tool-adapter.js +1 -0
  109. package/dist/vendor/core/adapt/trae-adapter.d.ts +8 -0
  110. package/dist/vendor/core/adapt/trae-adapter.js +19 -0
  111. package/dist/vendor/core/adapt/trae-cn-adapter.d.ts +8 -0
  112. package/dist/vendor/core/adapt/trae-cn-adapter.js +19 -0
  113. package/dist/vendor/core/agent-interaction.d.ts +58 -0
  114. package/dist/vendor/core/agent-interaction.js +58 -0
  115. package/dist/vendor/core/command-params.d.ts +5 -0
  116. package/dist/vendor/core/command-params.js +46 -0
  117. package/dist/vendor/core/index.d.ts +22 -0
  118. package/dist/vendor/core/index.js +22 -0
  119. package/dist/vendor/core/link/skill-links.d.ts +38 -0
  120. package/dist/vendor/core/link/skill-links.js +245 -0
  121. package/dist/vendor/core/link/tool-links.d.ts +83 -0
  122. package/dist/vendor/core/link/tool-links.js +376 -0
  123. package/dist/vendor/core/org/account-policy.d.ts +8 -0
  124. package/dist/vendor/core/org/account-policy.js +57 -0
  125. package/dist/vendor/core/org/org-name.d.ts +2 -0
  126. package/dist/vendor/core/org/org-name.js +22 -0
  127. package/dist/vendor/core/org/standing-teams.d.ts +10 -0
  128. package/dist/vendor/core/org/standing-teams.js +27 -0
  129. package/dist/vendor/core/schema/compatibility.d.ts +17 -0
  130. package/dist/vendor/core/schema/compatibility.js +45 -0
  131. package/dist/vendor/core/schema/release-manifest.d.ts +88 -0
  132. package/dist/vendor/core/schema/release-manifest.js +161 -0
  133. package/dist/vendor/core/schema/skill-json.d.ts +61 -0
  134. package/dist/vendor/core/schema/skill-json.js +47 -0
  135. package/dist/vendor/core/schema/validation-result.d.ts +7 -0
  136. package/dist/vendor/core/schema/validation-result.js +1 -0
  137. package/dist/vendor/core/skill/builtin-package.d.ts +32 -0
  138. package/dist/vendor/core/skill/builtin-package.js +143 -0
  139. package/dist/vendor/core/skill/directory-validator.d.ts +9 -0
  140. package/dist/vendor/core/skill/directory-validator.js +72 -0
  141. package/dist/vendor/core/skill/import-skill.d.ts +10 -0
  142. package/dist/vendor/core/skill/import-skill.js +68 -0
  143. package/dist/vendor/core/skill/published-package.d.ts +1 -0
  144. package/dist/vendor/core/skill/published-package.js +9 -0
  145. package/dist/vendor/core/skill/skill-md.d.ts +15 -0
  146. package/dist/vendor/core/skill/skill-md.js +32 -0
  147. package/dist/vendor/core/store/file-copy.d.ts +3 -0
  148. package/dist/vendor/core/store/file-copy.js +102 -0
  149. package/dist/vendor/core/store/local-store.d.ts +43 -0
  150. package/dist/vendor/core/store/local-store.js +104 -0
  151. package/dist/vendor/core/store/skill-store.d.ts +24 -0
  152. package/dist/vendor/core/store/skill-store.js +41 -0
  153. package/dist/vendor/core/store/skills-json.d.ts +34 -0
  154. package/dist/vendor/core/store/skills-json.js +146 -0
  155. package/dist/vendor/core/version/select-version.d.ts +16 -0
  156. package/dist/vendor/core/version/select-version.js +34 -0
  157. package/dist/vendor/core/version/version.d.ts +2 -0
  158. package/dist/vendor/core/version/version.js +25 -0
  159. package/dist/vendor/i18n/api-errors.d.ts +121 -0
  160. package/dist/vendor/i18n/api-errors.js +240 -0
  161. package/dist/vendor/i18n/i18n-runtime.d.ts +4 -0
  162. package/dist/vendor/i18n/i18n-runtime.js +16 -0
  163. package/dist/vendor/i18n/index.d.ts +5 -0
  164. package/dist/vendor/i18n/index.js +5 -0
  165. package/dist/vendor/i18n/locales.d.ts +9 -0
  166. package/dist/vendor/i18n/locales.js +33 -0
  167. package/dist/vendor/i18n/resources.d.ts +11 -0
  168. package/dist/vendor/i18n/resources.js +925 -0
  169. package/dist/vendor/i18n/translate-api-error.d.ts +8 -0
  170. package/dist/vendor/i18n/translate-api-error.js +12 -0
  171. package/dist/version.d.ts +1 -0
  172. package/dist/version.js +24 -0
  173. package/package.json +46 -0
@@ -0,0 +1,147 @@
1
+ import { isBuiltinIdentity, validateReleaseManifest } from '../vendor/core/index.js';
2
+ import { execFile } from 'node:child_process';
3
+ import fs from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import { promisify } from 'node:util';
6
+ import semver from 'semver';
7
+ const execFileAsync = promisify(execFile);
8
+ const EXPLICIT_SEMVER_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
9
+ function isBump(input) {
10
+ return input === 'major' || input === 'minor' || input === 'patch';
11
+ }
12
+ export function isValidExplicitVersion(input) {
13
+ return EXPLICIT_SEMVER_PATTERN.test(input);
14
+ }
15
+ export function nextVersion(current, bump) {
16
+ const next = semver.inc(current, bump);
17
+ if (!next) {
18
+ throw new Error(`Cannot bump invalid version: ${current}`);
19
+ }
20
+ return next;
21
+ }
22
+ async function isInsideGitRepo(dir) {
23
+ try {
24
+ await execFileAsync('git', ['rev-parse', '--is-inside-work-tree'], { cwd: dir });
25
+ return true;
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ async function hasCleanWorkingTree(dir) {
32
+ const { stdout } = await execFileAsync('git', ['status', '--porcelain'], { cwd: dir });
33
+ return stdout.trim().length === 0;
34
+ }
35
+ async function readManifest(dir) {
36
+ const manifestPath = path.join(dir, 'release.json');
37
+ let raw;
38
+ try {
39
+ raw = await fs.readFile(manifestPath, 'utf8');
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ let parsed;
45
+ try {
46
+ parsed = JSON.parse(raw);
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ const result = validateReleaseManifest(parsed);
52
+ if (result.success)
53
+ return { valid: true, data: result.data };
54
+ const isPreVersion = typeof parsed === 'object' &&
55
+ parsed !== null &&
56
+ parsed.schemaVersion === 1;
57
+ return { valid: false, isPreVersion, errors: result.errors };
58
+ }
59
+ async function readSkillJsonName(dir) {
60
+ try {
61
+ const raw = await fs.readFile(path.join(dir, 'skill.json'), 'utf8');
62
+ const data = JSON.parse(raw);
63
+ return data.name ?? null;
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ }
69
+ async function writeVersion(dir, version) {
70
+ const manifestPath = path.join(dir, 'release.json');
71
+ const raw = await fs.readFile(manifestPath, 'utf8');
72
+ const data = JSON.parse(raw);
73
+ // 保留现有 v3/v4 版本;仅把 schemaVersion 1(版本跟踪前)升级到 v4(ADR-0048)。
74
+ const manifestVersion = typeof data.schemaVersion === 'number' ? data.schemaVersion : 1;
75
+ data.schemaVersion = manifestVersion >= 3 ? manifestVersion : 4;
76
+ data.version = version;
77
+ await fs.writeFile(manifestPath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
78
+ }
79
+ async function commitAndTag(dir, version) {
80
+ const tag = `v${version}`;
81
+ await execFileAsync('git', ['add', 'release.json'], { cwd: dir });
82
+ const staged = (await execFileAsync('git', ['diff', '--cached', '--name-only'], { cwd: dir })).stdout.trim();
83
+ // Tagging the version the source already carries (the first release, where
84
+ // `init` seeded it) has nothing to commit — the tag is the whole point.
85
+ if (staged) {
86
+ await execFileAsync('git', ['commit', '-m', `chore: bump version to ${version}`], { cwd: dir });
87
+ }
88
+ await execFileAsync('git', ['tag', '-a', tag, '-m', `Release ${version}`], { cwd: dir });
89
+ }
90
+ async function readVersionInspection(directory) {
91
+ // Built-in identity check first — highest-priority rejection, regardless of directory shape
92
+ const skillName = await readSkillJsonName(directory);
93
+ if (skillName && isBuiltinIdentity(skillName)) {
94
+ throw new Error('Built-in skills cannot be versioned; their version is pinned to the ESL CLI version.');
95
+ }
96
+ // Check git — without a repo, we can't commit/tag
97
+ if (!(await isInsideGitRepo(directory))) {
98
+ throw new Error('This directory is not a git repository. Run `git init` and commit the skill source before using `esl version`.');
99
+ }
100
+ const manifestResult = await readManifest(directory);
101
+ // No release.json at all — this is not a source-form skill
102
+ if (manifestResult === null) {
103
+ throw new Error('No release.json found. `esl version` operates on a source-form skill directory (SKILL.md + release.json).');
104
+ }
105
+ if (!manifestResult.valid && manifestResult.isPreVersion) {
106
+ return { currentVersion: null, isPreVersion: true };
107
+ }
108
+ if (!manifestResult.valid) {
109
+ throw new Error(`Invalid release.json: ${manifestResult.errors.join(', ')}`);
110
+ }
111
+ return { currentVersion: manifestResult.data.version, isPreVersion: false };
112
+ }
113
+ async function assertCleanWorkingTree(directory) {
114
+ if (!(await hasCleanWorkingTree(directory))) {
115
+ throw new Error('Working tree is not clean. Commit or stash your changes before bumping the version so the version commit contains only the manifest change.');
116
+ }
117
+ }
118
+ export async function inspectVersion(directory) {
119
+ const inspection = await readVersionInspection(directory);
120
+ await assertCleanWorkingTree(directory);
121
+ return inspection;
122
+ }
123
+ export async function executeVersion(input, options = {}) {
124
+ const directory = options.cwd ?? process.cwd();
125
+ const inspection = await readVersionInspection(directory);
126
+ let newVersion;
127
+ if (isBump(input)) {
128
+ if (inspection.isPreVersion) {
129
+ throw new Error('This release manifest is from before version tracking (schemaVersion 1). Run `esl version <SemVer>` with an explicit version number to initialize versioning and upgrade the manifest to schemaVersion 4.');
130
+ }
131
+ if (!inspection.currentVersion) {
132
+ throw new Error('Cannot bump: no current version found in release.json.');
133
+ }
134
+ newVersion = nextVersion(inspection.currentVersion, input);
135
+ }
136
+ else {
137
+ // explicit SemVer — validate syntax
138
+ if (!isValidExplicitVersion(input)) {
139
+ throw new Error(`Invalid version: ${input}. Version must be valid SemVer (e.g. 1.2.3).`);
140
+ }
141
+ newVersion = input;
142
+ }
143
+ await assertCleanWorkingTree(directory);
144
+ await writeVersion(directory, newVersion);
145
+ await commitAndTag(directory, newVersion);
146
+ return newVersion;
147
+ }
@@ -0,0 +1,14 @@
1
+ import { type LocalStoreOptions, type OrganizationMembership } from '@esl/core';
2
+ export interface WhoamiResult {
3
+ loggedIn: boolean;
4
+ username: string | null;
5
+ organizations: OrganizationMembership[] | null;
6
+ /** 旧版(<org>_<username> 时代)配置残留:需要重新登录 */
7
+ legacyIdentity: boolean;
8
+ server: string | null;
9
+ loginAt: string | null;
10
+ expiresAt: string | null;
11
+ expired: boolean;
12
+ }
13
+ export declare function executeWhoami(options?: LocalStoreOptions): Promise<WhoamiResult>;
14
+ export declare function formatWhoami(result: WhoamiResult): string;
@@ -0,0 +1,54 @@
1
+ import { loadConfig, loadCredentials } from '../vendor/core/index.js';
2
+ import { isLoginFresh, resolveLoginTtlMs } from './network-options.js';
3
+ export async function executeWhoami(options = {}) {
4
+ const config = await loadConfig({ homeDir: options.homeDir });
5
+ const credentials = await loadCredentials({ homeDir: options.homeDir });
6
+ const token = credentials.token;
7
+ const loginAt = credentials.loginAt;
8
+ const loginAtMs = loginAt ? Date.parse(loginAt) : NaN;
9
+ const expired = !isLoginFresh(loginAt);
10
+ return {
11
+ loggedIn: Boolean(token),
12
+ username: config.username ?? null,
13
+ organizations: config.organizations ?? null,
14
+ legacyIdentity: config.legacyIdentity ?? false,
15
+ server: config.server ?? null,
16
+ loginAt,
17
+ expiresAt: loginAt && !Number.isNaN(loginAtMs) ? new Date(loginAtMs + resolveLoginTtlMs()).toISOString() : null,
18
+ expired
19
+ };
20
+ }
21
+ export function formatWhoami(result) {
22
+ if (!result.loggedIn) {
23
+ return 'Not logged in. Run esl login to authenticate.';
24
+ }
25
+ const lines = [];
26
+ if (result.legacyIdentity) {
27
+ lines.push('Notice: this login predates the global identity model; run `esl login` again.');
28
+ }
29
+ if (result.username) {
30
+ lines.push(`Username: ${result.username}`);
31
+ }
32
+ if (result.organizations && result.organizations.length > 0) {
33
+ // 括号里是组织内身份(ADR-0038):所有者成员 / 管理成员 / 普通成员,由常设团队
34
+ // 成员身份推导。组织内没有角色,这里标注的始终是团队身份。
35
+ const rendered = result.organizations
36
+ .map((membership) => `${membership.org} (${membership.identity})`)
37
+ .join(', ');
38
+ lines.push(`Organization memberships: ${rendered}`);
39
+ }
40
+ else if (result.organizations) {
41
+ lines.push('Organization memberships: none');
42
+ }
43
+ if (result.server) {
44
+ lines.push(`Server: ${result.server}`);
45
+ }
46
+ if (result.loginAt) {
47
+ lines.push(`Logged in at: ${result.loginAt}`);
48
+ }
49
+ if (result.expiresAt) {
50
+ lines.push(`Expires at: ${result.expiresAt}`);
51
+ }
52
+ lines.push(result.expired ? 'Status: expired (run esl login to re-authenticate)' : 'Status: active');
53
+ return lines.join('\n');
54
+ }
@@ -0,0 +1,24 @@
1
+ export declare const CLI_NAME = "esl";
2
+ export * from './commands/init.js';
3
+ export * from './commands/admin.js';
4
+ export * from './commands/adapt.js';
5
+ export * from './commands/source.js';
6
+ export * from './commands/list.js';
7
+ export * from './commands/use.js';
8
+ export * from './commands/info.js';
9
+ export * from './commands/install.js';
10
+ export * from './commands/login.js';
11
+ export * from './commands/publish.js';
12
+ export * from './commands/deprecate.js';
13
+ export * from './commands/release-delete.js';
14
+ export * from './commands/rename.js';
15
+ export * from './commands/repair-tag.js';
16
+ export * from './commands/upload.js';
17
+ export * from './commands/reset-source.js';
18
+ export * from './commands/search.js';
19
+ export * from './commands/update.js';
20
+ export * from './commands/uninstall.js';
21
+ export * from './commands/validate.js';
22
+ export * from './commands/link.js';
23
+ export * from './commands/unlink.js';
24
+ export * from './commands/version.js';
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ export const CLI_NAME = 'esl';
2
+ export * from './commands/init.js';
3
+ export * from './commands/admin.js';
4
+ export * from './commands/adapt.js';
5
+ export * from './commands/source.js';
6
+ export * from './commands/list.js';
7
+ export * from './commands/use.js';
8
+ export * from './commands/info.js';
9
+ export * from './commands/install.js';
10
+ export * from './commands/login.js';
11
+ export * from './commands/publish.js';
12
+ export * from './commands/deprecate.js';
13
+ export * from './commands/release-delete.js';
14
+ export * from './commands/rename.js';
15
+ export * from './commands/repair-tag.js';
16
+ export * from './commands/upload.js';
17
+ export * from './commands/reset-source.js';
18
+ export * from './commands/search.js';
19
+ export * from './commands/update.js';
20
+ export * from './commands/uninstall.js';
21
+ export * from './commands/validate.js';
22
+ export * from './commands/link.js';
23
+ export * from './commands/unlink.js';
24
+ export * from './commands/version.js';
@@ -0,0 +1 @@
1
+ export declare function notify(message: string): void;
package/dist/output.js ADDED
@@ -0,0 +1,3 @@
1
+ export function notify(message) {
2
+ process.stderr.write(`${message}\n`);
3
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { syncGlobalBuiltinSkill } from './commands/sync-builtin.js';
2
+ try {
3
+ await syncGlobalBuiltinSkill({});
4
+ }
5
+ catch (error) {
6
+ const message = error instanceof Error ? error.message : String(error);
7
+ console.error(`esl: built-in skill global sync deferred: ${message}`);
8
+ }
@@ -0,0 +1,9 @@
1
+ export interface PromptStreams {
2
+ input?: NodeJS.ReadableStream;
3
+ output?: NodeJS.WritableStream;
4
+ }
5
+ export declare function readHidden(prompt: string, streams?: PromptStreams): Promise<string>;
6
+ export declare function readText(prompt: string, streams?: PromptStreams): Promise<string>;
7
+ export declare function confirm(question: string, streams?: PromptStreams): Promise<boolean>;
8
+ export declare function isInteractive(): boolean;
9
+ export declare function readStdinText(input?: NodeJS.ReadableStream): Promise<string>;
package/dist/prompt.js ADDED
@@ -0,0 +1,24 @@
1
+ import { confirm as confirmPrompt, input, password } from '@inquirer/prompts';
2
+ export function readHidden(prompt, streams = {}) {
3
+ return password({ message: prompt, mask: false, toggleMask: false }, streams);
4
+ }
5
+ export function readText(prompt, streams = {}) {
6
+ return input({ message: prompt }, streams);
7
+ }
8
+ export function confirm(question, streams = {}) {
9
+ return confirmPrompt({ message: question, default: false }, streams);
10
+ }
11
+ export function isInteractive() {
12
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
13
+ }
14
+ export function readStdinText(input = process.stdin) {
15
+ return new Promise((resolve, reject) => {
16
+ let data = '';
17
+ input.setEncoding('utf8');
18
+ input.on('data', (chunk) => {
19
+ data += chunk;
20
+ });
21
+ input.on('end', () => resolve(data));
22
+ input.on('error', reject);
23
+ });
24
+ }
@@ -0,0 +1,24 @@
1
+ import { type LocalStoreOptions } from '../store/local-store.js';
2
+ import { type ToolName } from '../link/tool-links.js';
3
+ export interface AdaptResult {
4
+ tool: string;
5
+ skills: AdaptedSkillResult[];
6
+ adopted: AdaptedSkillResult[];
7
+ skipped: AdaptedSkillTargetResult[];
8
+ conflicts: AdaptedSkillTargetResult[];
9
+ failed: AdaptedSkillTargetResult[];
10
+ }
11
+ export interface AdaptedSkillResult {
12
+ identity: string;
13
+ directoryName: string;
14
+ }
15
+ export interface AdaptedSkillTargetResult extends AdaptedSkillResult {
16
+ targetDir: string;
17
+ }
18
+ interface AdaptOptions extends LocalStoreOptions {
19
+ tools?: ToolName[];
20
+ force?: boolean;
21
+ }
22
+ export declare function adaptProject(projectRoot: string, options?: AdaptOptions): Promise<AdaptResult[]>;
23
+ export declare function adaptGlobal(options?: AdaptOptions): Promise<AdaptResult[]>;
24
+ export {};
@@ -0,0 +1,99 @@
1
+ import { loadConfig, resolveLocalStorePaths, resolveProjectStorePaths } from '../store/local-store.js';
2
+ import { loadSkillsJson } from '../store/skills-json.js';
3
+ import { isSupportedTool, SUPPORTED_TOOLS, syncToolLinks } from '../link/tool-links.js';
4
+ function directoryName(identity) {
5
+ const [, scope, skillName] = identity.split('/');
6
+ return `${scope}_${skillName}`;
7
+ }
8
+ function toSkill(identity) {
9
+ return { identity, directoryName: directoryName(identity) };
10
+ }
11
+ function toTarget(result) {
12
+ return { ...toSkill(result.identity), targetDir: result.targetDir };
13
+ }
14
+ function groupResults(results) {
15
+ const byTool = new Map();
16
+ for (const result of results) {
17
+ let entry = byTool.get(result.tool);
18
+ if (!entry) {
19
+ entry = {
20
+ tool: result.tool,
21
+ skills: [],
22
+ adopted: [],
23
+ skipped: [],
24
+ conflicts: [],
25
+ failed: []
26
+ };
27
+ byTool.set(result.tool, entry);
28
+ }
29
+ entry.skills.push(toSkill(result.identity));
30
+ if (result.status === 'created') {
31
+ entry.adopted.push(toTarget(result));
32
+ }
33
+ else if (result.status === 'existing') {
34
+ entry.skipped.push(toTarget(result));
35
+ }
36
+ else if (result.status === 'conflict') {
37
+ entry.conflicts.push(toTarget(result));
38
+ }
39
+ else if (result.status === 'failed') {
40
+ entry.failed.push(toTarget(result));
41
+ }
42
+ }
43
+ return Array.from(byTool.values());
44
+ }
45
+ async function resolveProjectTools(projectRoot, options) {
46
+ if (options.tools && options.tools.length > 0) {
47
+ return options.tools;
48
+ }
49
+ const skillsJson = await loadSkillsJson(projectRoot);
50
+ if (skillsJson.tools && skillsJson.tools.length > 0) {
51
+ return toConfiguredTools(skillsJson.tools);
52
+ }
53
+ const config = await loadConfig(options);
54
+ return toConfiguredTools(config.tools);
55
+ }
56
+ async function resolveGlobalTools(options) {
57
+ if (options.tools && options.tools.length > 0) {
58
+ return options.tools;
59
+ }
60
+ const config = await loadConfig(options);
61
+ return toConfiguredTools(config.tools);
62
+ }
63
+ function toConfiguredTools(tools) {
64
+ return tools.map((tool) => {
65
+ if (!isSupportedTool(tool)) {
66
+ throw new Error(`Unknown tool: ${tool}. Supported tools: ${SUPPORTED_TOOLS.join(', ')}`);
67
+ }
68
+ return tool;
69
+ });
70
+ }
71
+ export async function adaptProject(projectRoot, options = {}) {
72
+ const tools = await resolveProjectTools(projectRoot, options);
73
+ if (tools.length === 0) {
74
+ throw new Error('No tools configured. Run: esl install --tools <tools>');
75
+ }
76
+ const results = await syncToolLinks({
77
+ storeRoot: resolveProjectStorePaths(projectRoot).root,
78
+ level: 'project',
79
+ tools,
80
+ projectRoot,
81
+ homeDir: options.homeDir,
82
+ force: options.force
83
+ });
84
+ return groupResults(results);
85
+ }
86
+ export async function adaptGlobal(options = {}) {
87
+ const tools = await resolveGlobalTools(options);
88
+ if (tools.length === 0) {
89
+ throw new Error('No tools configured. Run: esl install --tools <tools>');
90
+ }
91
+ const results = await syncToolLinks({
92
+ storeRoot: resolveLocalStorePaths(options).root,
93
+ level: 'global',
94
+ tools,
95
+ homeDir: options.homeDir,
96
+ force: options.force
97
+ });
98
+ return groupResults(results);
99
+ }
@@ -0,0 +1,2 @@
1
+ import type { AdaptedSkill } from './tool-adapter.js';
2
+ export declare function copyAdaptedSkill(skillSourceDir: string, skill: AdaptedSkill, targetBaseDir: string): Promise<void>;
@@ -0,0 +1,17 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { copySkillDirectory } from '../store/file-copy.js';
4
+ export async function copyAdaptedSkill(skillSourceDir, skill, targetBaseDir) {
5
+ const targetDir = path.join(targetBaseDir, skill.directoryName);
6
+ await copySkillDirectory(skillSourceDir, targetDir);
7
+ await rewriteSkillMdName(path.join(targetDir, 'SKILL.md'), skill.displayName);
8
+ }
9
+ async function rewriteSkillMdName(skillMdPath, displayName) {
10
+ const content = await fs.readFile(skillMdPath, 'utf8');
11
+ const updated = content.replace(/^(---\r?\n)([\s\S]*?)(\r?\n---)/, (_match, open, frontmatter, close) => {
12
+ return `${open}${frontmatter.replace(/(^name:\s*)[^\r\n]+/m, `$1${displayName}`)}${close}`;
13
+ });
14
+ await fs.chmod(skillMdPath, 0o666);
15
+ await fs.writeFile(skillMdPath, updated, 'utf8');
16
+ await fs.chmod(skillMdPath, 0o444);
17
+ }
@@ -0,0 +1,8 @@
1
+ import type { AdaptedSkill, ToolAdapter } from './tool-adapter.js';
2
+ export declare class ClaudeAdapter implements ToolAdapter {
3
+ readonly name = "claude";
4
+ projectDir(root: string): string;
5
+ globalDir(homeDir?: string): string;
6
+ adapt(skillSourceDir: string, skill: AdaptedSkill, targetBaseDir: string): Promise<void>;
7
+ clean(targetBaseDir: string): Promise<void>;
8
+ }
@@ -0,0 +1,19 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { removeDirectory } from '../store/file-copy.js';
4
+ import { copyAdaptedSkill } from './adapted-skill-copy.js';
5
+ export class ClaudeAdapter {
6
+ name = 'claude';
7
+ projectDir(root) {
8
+ return path.join(root, '.claude', 'skills');
9
+ }
10
+ globalDir(homeDir = os.homedir()) {
11
+ return path.join(homeDir, '.claude', 'skills');
12
+ }
13
+ async adapt(skillSourceDir, skill, targetBaseDir) {
14
+ await copyAdaptedSkill(skillSourceDir, skill, targetBaseDir);
15
+ }
16
+ async clean(targetBaseDir) {
17
+ await removeDirectory(targetBaseDir);
18
+ }
19
+ }
@@ -0,0 +1,8 @@
1
+ import type { AdaptedSkill, ToolAdapter } from './tool-adapter.js';
2
+ export declare class CodexAdapter implements ToolAdapter {
3
+ readonly name = "codex";
4
+ projectDir(root: string): string;
5
+ globalDir(homeDir?: string): string;
6
+ adapt(skillSourceDir: string, skill: AdaptedSkill, targetBaseDir: string): Promise<void>;
7
+ clean(targetBaseDir: string): Promise<void>;
8
+ }
@@ -0,0 +1,19 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { removeDirectory } from '../store/file-copy.js';
4
+ import { copyAdaptedSkill } from './adapted-skill-copy.js';
5
+ export class CodexAdapter {
6
+ name = 'codex';
7
+ projectDir(root) {
8
+ return path.join(root, '.agents', 'skills');
9
+ }
10
+ globalDir(homeDir = os.homedir()) {
11
+ return path.join(homeDir, '.agents', 'skills');
12
+ }
13
+ async adapt(skillSourceDir, skill, targetBaseDir) {
14
+ await copyAdaptedSkill(skillSourceDir, skill, targetBaseDir);
15
+ }
16
+ async clean(targetBaseDir) {
17
+ await removeDirectory(targetBaseDir);
18
+ }
19
+ }
@@ -0,0 +1,2 @@
1
+ export { adaptGlobal, adaptProject, type AdaptResult } from './adapt-engine.js';
2
+ export { SUPPORTED_TOOLS, isSupportedTool, parseToolSelection, toolDirectory, type ToolName } from '../link/tool-links.js';
@@ -0,0 +1,2 @@
1
+ export { adaptGlobal, adaptProject } from './adapt-engine.js';
2
+ export { SUPPORTED_TOOLS, isSupportedTool, parseToolSelection, toolDirectory } from '../link/tool-links.js';
@@ -0,0 +1,12 @@
1
+ export interface AdaptedSkill {
2
+ identity: string;
3
+ directoryName: string;
4
+ displayName: string;
5
+ }
6
+ export interface ToolAdapter {
7
+ name: string;
8
+ projectDir(root: string): string;
9
+ globalDir(homeDir?: string): string;
10
+ adapt(skillSourceDir: string, skill: AdaptedSkill, targetBaseDir: string): Promise<void>;
11
+ clean(targetBaseDir: string): Promise<void>;
12
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { AdaptedSkill, ToolAdapter } from './tool-adapter.js';
2
+ export declare class TraeAdapter implements ToolAdapter {
3
+ readonly name = "trae";
4
+ projectDir(root: string): string;
5
+ globalDir(homeDir?: string): string;
6
+ adapt(skillSourceDir: string, skill: AdaptedSkill, targetBaseDir: string): Promise<void>;
7
+ clean(targetBaseDir: string): Promise<void>;
8
+ }
@@ -0,0 +1,19 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { removeDirectory } from '../store/file-copy.js';
4
+ import { copyAdaptedSkill } from './adapted-skill-copy.js';
5
+ export class TraeAdapter {
6
+ name = 'trae';
7
+ projectDir(root) {
8
+ return path.join(root, '.trae', 'skills');
9
+ }
10
+ globalDir(homeDir = os.homedir()) {
11
+ return path.join(homeDir, '.trae', 'skills');
12
+ }
13
+ async adapt(skillSourceDir, skill, targetBaseDir) {
14
+ await copyAdaptedSkill(skillSourceDir, skill, targetBaseDir);
15
+ }
16
+ async clean(targetBaseDir) {
17
+ await removeDirectory(targetBaseDir);
18
+ }
19
+ }
@@ -0,0 +1,8 @@
1
+ import type { AdaptedSkill, ToolAdapter } from './tool-adapter.js';
2
+ export declare class TraeCnAdapter implements ToolAdapter {
3
+ readonly name = "trae-cn";
4
+ projectDir(root: string): string;
5
+ globalDir(homeDir?: string): string;
6
+ adapt(skillSourceDir: string, skill: AdaptedSkill, targetBaseDir: string): Promise<void>;
7
+ clean(targetBaseDir: string): Promise<void>;
8
+ }
@@ -0,0 +1,19 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { removeDirectory } from '../store/file-copy.js';
4
+ import { copyAdaptedSkill } from './adapted-skill-copy.js';
5
+ export class TraeCnAdapter {
6
+ name = 'trae-cn';
7
+ projectDir(root) {
8
+ return path.join(root, '.trae', 'skills');
9
+ }
10
+ globalDir(homeDir = os.homedir()) {
11
+ return path.join(homeDir, '.trae-cn', 'skills');
12
+ }
13
+ async adapt(skillSourceDir, skill, targetBaseDir) {
14
+ await copyAdaptedSkill(skillSourceDir, skill, targetBaseDir);
15
+ }
16
+ async clean(targetBaseDir) {
17
+ await removeDirectory(targetBaseDir);
18
+ }
19
+ }