@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,252 @@
1
+ import { execFile } from 'node:child_process';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { promisify } from 'node:util';
5
+ import { AgentInteractionRequiredError, createAgentInteractionRequest, createMinimalReleaseManifest, loadConfig, titleCaseDisplayName, validateSkillMd, validateSkillSourceDirectory } from '../vendor/core/index.js';
6
+ import { notify } from '../output.js';
7
+ import { isInteractive, readText } from '../prompt.js';
8
+ import { apiUrl, fetchWithTimeout, resolveOptionalFreshToken } from './network-options.js';
9
+ const execFileAsync = promisify(execFile);
10
+ /**
11
+ * YAML frontmatter is line-oriented, so a description containing a colon, a
12
+ * quote, or a leading special character has to be quoted to keep the generated
13
+ * SKILL.md parseable.
14
+ */
15
+ function yamlScalar(value) {
16
+ return /^[A-Za-z0-9][A-Za-z0-9 .,;!?'()\-/]*$/.test(value) ? value : JSON.stringify(value);
17
+ }
18
+ function isValidSkillName(name) {
19
+ return /^[a-z0-9-]{1,64}$/.test(name);
20
+ }
21
+ function normalizeNamespace(value) {
22
+ const namespace = value.trim().replace(/^@/, '');
23
+ if (!namespace || namespace === 'personal')
24
+ return null;
25
+ if (!isValidSkillName(namespace)) {
26
+ throw new Error('Namespace must be "personal" or use lowercase letters, digits, and hyphens (1-64 characters)');
27
+ }
28
+ return namespace;
29
+ }
30
+ // namespace 菜单的数据来源:优先实时查询服务端组织列表,请求失败或未登录时
31
+ // 回退登录时缓存的成员关系;两者都没有则返回 null,由调用方退回手输提示。
32
+ // 整个解析尽力而为,绝不阻断离线的 init。
33
+ async function resolveNamespaceChoices(options) {
34
+ const config = await loadConfig({ homeDir: options.homeDir }).catch(() => null);
35
+ let memberships = null;
36
+ const token = await resolveOptionalFreshToken(options);
37
+ if (token && config?.server) {
38
+ try {
39
+ const fetchImpl = options.customFetch ?? fetch;
40
+ const response = await fetchWithTimeout(fetchImpl, apiUrl(config.server, '/api/orgs/mine'), { headers: { Authorization: `token ${token}` } },
41
+ // 菜单是锦上添花:网络不健康时快速回退,不让 init 卡在超时上。
42
+ 3_000);
43
+ if (response.ok) {
44
+ const data = (await response.json());
45
+ memberships = Array.isArray(data.organizations)
46
+ ? data.organizations.filter((membership) => !membership.status || membership.status === 'active')
47
+ : [];
48
+ }
49
+ }
50
+ catch {
51
+ // Fall back to the login-time cache below.
52
+ }
53
+ }
54
+ if (!memberships && config?.organizations) {
55
+ memberships = config.organizations;
56
+ }
57
+ return memberships ? memberships.map((membership) => membership.org) : null;
58
+ }
59
+ export async function executeInit(options = {}) {
60
+ const runGitInit = options.runGitInit ?? true;
61
+ const targetDir = path.resolve(options.directory ?? process.cwd());
62
+ await fs.mkdir(targetDir, { recursive: true });
63
+ // 已有 SKILL.md 是身份权威:存在则以它为准,绝不改写;非法时记录警告,
64
+ // 严格校验留给 validate/upload,init 只管补缺。
65
+ const skillMdPath = path.join(targetDir, 'SKILL.md');
66
+ const existingSkillMd = await fs.readFile(skillMdPath, 'utf8').then((content) => content, () => undefined);
67
+ let skillName;
68
+ if (existingSkillMd !== undefined) {
69
+ const parsed = validateSkillMd(existingSkillMd);
70
+ if (parsed.success) {
71
+ skillName = parsed.data.name;
72
+ if (options.name !== undefined && options.name !== skillName) {
73
+ notify(`SKILL.md declares the name ${skillName}; ignoring --name ${options.name}.`);
74
+ }
75
+ }
76
+ else {
77
+ notify(`SKILL.md exists but is not a valid ESL skill source: ${parsed.errors.join(', ')}`);
78
+ notify('Leaving SKILL.md untouched; only filling in the missing release manifest.');
79
+ }
80
+ }
81
+ const generateSkillMd = existingSkillMd === undefined;
82
+ if (generateSkillMd) {
83
+ skillName = options.name ?? path.basename(targetDir);
84
+ if (!isValidSkillName(skillName)) {
85
+ throw new Error(`Skill name must use lowercase letters, digits, and hyphens (1-64 characters); pass one via --name: got ${skillName}`);
86
+ }
87
+ }
88
+ const releaseJsonPath = path.join(targetDir, 'release.json');
89
+ const generateReleaseJson = !(await fs
90
+ .access(releaseJsonPath)
91
+ .then(() => true, () => false));
92
+ const defaultDescription = `Use when a user needs the ${skillName} workflow or domain guidance.`;
93
+ const defaultName = skillName ?? path.basename(targetDir);
94
+ const displayNameSeed = titleCaseDisplayName(defaultName);
95
+ let description = options.description ?? defaultDescription;
96
+ let displayName = options.displayName ?? (generateReleaseJson ? displayNameSeed : undefined);
97
+ let license = options.license ?? 'MIT';
98
+ let keywords = options.keywords ?? [];
99
+ let namespace;
100
+ if (options.agentInteraction && !options.noInput) {
101
+ const fields = [];
102
+ if (generateSkillMd && options.description === undefined) {
103
+ fields.push({
104
+ id: 'description',
105
+ kind: 'text',
106
+ label: 'Skill description',
107
+ required: true,
108
+ default: defaultDescription
109
+ });
110
+ }
111
+ if (generateReleaseJson && options.license === undefined) {
112
+ fields.push({
113
+ id: 'license',
114
+ kind: 'text',
115
+ label: 'License',
116
+ required: true,
117
+ default: 'MIT'
118
+ });
119
+ }
120
+ if (generateReleaseJson && options.keywords === undefined) {
121
+ fields.push({
122
+ id: 'keywords',
123
+ kind: 'multiselect',
124
+ label: 'Keywords',
125
+ required: false,
126
+ default: []
127
+ });
128
+ }
129
+ if (generateReleaseJson && options.displayName === undefined) {
130
+ fields.push({
131
+ id: 'displayName',
132
+ kind: 'text',
133
+ label: 'Display name',
134
+ required: false,
135
+ default: displayNameSeed
136
+ });
137
+ }
138
+ if (generateReleaseJson && options.namespace === undefined) {
139
+ const choices = await resolveNamespaceChoices(options);
140
+ fields.push({
141
+ id: 'namespace',
142
+ kind: choices ? 'select' : 'text',
143
+ label: 'Namespace',
144
+ required: true,
145
+ default: 'personal',
146
+ options: choices ? ['personal', ...choices] : undefined
147
+ });
148
+ }
149
+ if (fields.length > 0) {
150
+ throw new AgentInteractionRequiredError(createAgentInteractionRequest({
151
+ command: 'init',
152
+ fields,
153
+ requestId: options.interactionRequestId,
154
+ agentTool: options.agentTool
155
+ }));
156
+ }
157
+ }
158
+ // Interactive terminals get asked; scripts and --no-input keep the template.
159
+ const ask = options.promptText ?? (isInteractive() ? readText : undefined);
160
+ if (ask && !options.noInput) {
161
+ if (generateSkillMd && options.description === undefined) {
162
+ const answer = (await ask(`Description [${defaultDescription}]: `, defaultDescription)).trim();
163
+ description = answer || defaultDescription;
164
+ }
165
+ if (generateReleaseJson && options.license === undefined) {
166
+ const answer = (await ask('License (SPDX) [MIT]: ', 'MIT')).trim();
167
+ license = answer || 'MIT';
168
+ }
169
+ if (generateReleaseJson && options.keywords === undefined) {
170
+ const answer = (await ask('Keywords (comma separated) [none]: ', '')).trim();
171
+ keywords = answer
172
+ .split(',')
173
+ .map((keyword) => keyword.trim())
174
+ .filter((keyword) => keyword.length > 0);
175
+ }
176
+ if (generateReleaseJson && options.displayName === undefined) {
177
+ const answer = (await ask(`Display name [${displayNameSeed}]: `, displayNameSeed)).trim();
178
+ displayName = answer || displayNameSeed;
179
+ }
180
+ if (generateReleaseJson && options.namespace === undefined) {
181
+ const choices = await resolveNamespaceChoices(options);
182
+ if (choices) {
183
+ // 编号选择:1 固定为 personal,其余为所在组织;也接受直接输入组织名。
184
+ const menu = [
185
+ 'Namespace:',
186
+ ' 1. personal (default)',
187
+ ...choices.map((org, index) => ` ${index + 2}. @${org}`)
188
+ ].join('\n');
189
+ notify(menu);
190
+ while (true) {
191
+ const answer = (await ask('Select namespace [1]: ', '1')).trim().replace(/^@/, '');
192
+ if (!answer || answer === '1' || answer === 'personal')
193
+ break;
194
+ if (/^\d+$/.test(answer)) {
195
+ const org = choices[Number(answer) - 2];
196
+ if (org) {
197
+ namespace = org;
198
+ break;
199
+ }
200
+ }
201
+ else if (choices.includes(answer)) {
202
+ namespace = answer;
203
+ break;
204
+ }
205
+ notify(`Invalid namespace; enter 1-${choices.length + 1}, "personal", or an organization name.`);
206
+ }
207
+ }
208
+ else {
209
+ const answer = (await ask('Namespace (personal or organization) [personal]: ', 'personal')).trim();
210
+ namespace = normalizeNamespace(answer || 'personal');
211
+ }
212
+ }
213
+ }
214
+ if (generateReleaseJson) {
215
+ // v4 的 name 是归属声明(ADR-0032):默认裸名,由服务端按上传者补全
216
+ // 个人命名空间;组织归属必须显式选择,避免静默推断不可逆身份。
217
+ namespace ??= options.namespace === undefined ? null : normalizeNamespace(options.namespace);
218
+ const scopedName = namespace ? `@${namespace}/${defaultName}` : defaultName;
219
+ const releaseJson = { ...createMinimalReleaseManifest(scopedName, license, displayName), keywords };
220
+ await fs.writeFile(releaseJsonPath, `${JSON.stringify(releaseJson, null, 2)}\n`, 'utf8');
221
+ }
222
+ if (generateSkillMd) {
223
+ await fs.writeFile(skillMdPath, `---
224
+ name: ${skillName}
225
+ description: ${yamlScalar(description)}
226
+ ---
227
+
228
+ # ${skillName}
229
+
230
+ Write concise agent instructions here. Move long reference material into references/, reusable scripts into scripts/, and output templates or assets into assets/.
231
+ `, 'utf8');
232
+ const validation = await validateSkillSourceDirectory(targetDir);
233
+ if (!validation.success) {
234
+ throw new Error(`Generated invalid skill source: ${validation.errors.join(', ')}`);
235
+ }
236
+ }
237
+ if (runGitInit) {
238
+ // 目标已在 git 仓库内(含父级仓库)时静默跳过,避免覆盖既有的仓库状态。
239
+ let alreadyRepo = false;
240
+ try {
241
+ await execFileAsync('git', ['rev-parse', '--is-inside-work-tree'], { cwd: targetDir });
242
+ alreadyRepo = true;
243
+ }
244
+ catch {
245
+ alreadyRepo = false;
246
+ }
247
+ if (!alreadyRepo) {
248
+ await execFileAsync('git', ['init'], { cwd: targetDir });
249
+ }
250
+ }
251
+ return targetDir;
252
+ }
@@ -0,0 +1,17 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { type ToolName } from '@esl/core';
3
+ import { type NetworkCommandOptions } from './network-options.js';
4
+ declare const defaultExecFileAsync: typeof execFile.__promisify__;
5
+ export interface InstallOptions extends NetworkCommandOptions {
6
+ version?: string;
7
+ global?: boolean;
8
+ noAdapt?: boolean;
9
+ tools?: ToolName[];
10
+ force?: boolean;
11
+ ignoreCompatibility?: boolean;
12
+ projectRoot?: string;
13
+ execFileAsync?: typeof defaultExecFileAsync;
14
+ }
15
+ export declare function resolveDefaultInstallTools(projectRoot: string, options: InstallOptions): Promise<ToolName[]>;
16
+ export declare function executeInstall(nameOrPath: string, options?: InstallOptions): Promise<string>;
17
+ export {};