openclaw-skills-cli 0.1.2 → 0.1.3

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.
@@ -37,6 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.installCommand = void 0;
40
+ exports.installToolOrDomain = installToolOrDomain;
40
41
  const commander_1 = require("commander");
41
42
  const chalk_1 = __importDefault(require("chalk"));
42
43
  const ora_1 = __importDefault(require("ora"));
@@ -46,6 +47,7 @@ const os = __importStar(require("node:os"));
46
47
  const prompts_1 = require("@inquirer/prompts");
47
48
  const client_js_1 = require("../api/client.js");
48
49
  const errors_js_1 = require("../utils/errors.js");
50
+ const paidRemoteStub_js_1 = require("../templates/paidRemoteStub.js");
49
51
  function parseSkillArg(arg) {
50
52
  const atIndex = arg.lastIndexOf('@');
51
53
  let fullName;
@@ -139,23 +141,41 @@ async function installToolOrDomain(namespace, name, targetVersion, installConfig
139
141
  fs.rmSync(installDir, { recursive: true, force: true });
140
142
  }
141
143
  const spinner = (0, ora_1.default)(`Instalando ${chalk_1.default.cyan(namespace)}/${chalk_1.default.bold(name)}${chalk_1.default.gray('@' + targetVersion)}...`).start();
142
- // Try direct download from filesUrl first, fallback to API
143
- const installConfigData = await (0, client_js_1.getInstallConfig)(namespace, name);
144
+ const isPaidRemoteOnly = Boolean(installConfig.remoteExecutionOnly || (installConfig.tier && installConfig.tier !== 'free'));
145
+ if (isPaidRemoteOnly) {
146
+ const tier = installConfig.tier || 'pro';
147
+ const executeEndpoint = installConfig.executeEndpoint || `/v1/skills/${namespace}/${name}/execute`;
148
+ fs.mkdirSync(installDir, { recursive: true });
149
+ fs.writeFileSync(path.join(installDir, 'SKILL.md'), (0, paidRemoteStub_js_1.buildPaidStubSkillMd)({
150
+ namespace,
151
+ name,
152
+ tier,
153
+ authorizeEndpoint: installConfig.authorizeEndpoint || null,
154
+ executeEndpoint,
155
+ }), 'utf-8');
156
+ fs.writeFileSync(path.join(installDir, 'manifest.json'), JSON.stringify((0, paidRemoteStub_js_1.buildPaidStubManifest)({
157
+ namespace,
158
+ name,
159
+ tier,
160
+ authorizeEndpoint: installConfig.authorizeEndpoint || null,
161
+ executeEndpoint,
162
+ }), null, 2), 'utf-8');
163
+ spinner.succeed(chalk_1.default.green(`Instalado en modo remoto (stub local) en ~/.openclaw/skills/${namespace}/${name}/`));
164
+ return;
165
+ }
144
166
  let filesData;
145
- if ('filesUrl' in installConfigData && installConfigData.filesUrl) {
167
+ if (installConfig.filesUrl) {
146
168
  // Download from Supabase Storage
147
- const response = await fetch(installConfigData.filesUrl);
169
+ const response = await fetch(installConfig.filesUrl);
148
170
  if (response.ok) {
149
171
  filesData = await response.json();
150
172
  }
151
173
  else {
152
- // Fallback to version API
153
- const versionData = await (0, client_js_1.getVersion)(namespace, name, targetVersion);
154
- filesData = versionData.files || {};
174
+ throw new Error(`No se pudieron descargar archivos desde filesUrl (${response.status})`);
155
175
  }
156
176
  }
157
177
  else {
158
- filesData = installConfigData.files || {};
178
+ filesData = installConfig.files || {};
159
179
  }
160
180
  // Handle both formats: object (new) or base64 tarball (legacy)
161
181
  if (typeof filesData === 'string') {
@@ -181,12 +201,6 @@ async function installToolOrDomain(namespace, name, targetVersion, installConfig
181
201
  fs.writeFileSync(fullPath, content, 'utf-8');
182
202
  }
183
203
  }
184
- try {
185
- await (0, client_js_1.registerInstall)(namespace, name, targetVersion);
186
- }
187
- catch {
188
- // Install tracking is best-effort
189
- }
190
204
  spinner.succeed(chalk_1.default.green(`Instalado en ~/.openclaw/skills/${namespace}/${name}/`));
191
205
  }
192
206
  async function installMcpServer(name, mcpConfig, targets, targetFlag) {
@@ -238,6 +252,7 @@ exports.installCommand = new commander_1.Command('install')
238
252
  let namespace;
239
253
  let name;
240
254
  let version;
255
+ let skillTier = 'free';
241
256
  if (opts.licenseToken) {
242
257
  const consumed = await (0, client_js_1.consumeInstallPack)(opts.licenseToken);
243
258
  if (!consumed.ok || !consumed.install) {
@@ -256,17 +271,14 @@ exports.installCommand = new commander_1.Command('install')
256
271
  name = parsed.name;
257
272
  version = parsed.version;
258
273
  }
259
- // Resolve version
260
- let targetVersion = version;
261
- if (!targetVersion) {
262
- const skill = await (0, client_js_1.getSkill)(namespace, name);
263
- const latest = skill.versions?.[0];
264
- if (!latest) {
265
- console.log(chalk_1.default.red('Este skill no tiene versiones publicadas'));
266
- return;
267
- }
268
- targetVersion = latest.version;
274
+ const skill = await (0, client_js_1.getSkill)(namespace, name);
275
+ const latest = skill.versions?.[0];
276
+ skillTier = skill.tier || 'free';
277
+ if (!latest && !version) {
278
+ console.log(chalk_1.default.red('Este skill no tiene versiones publicadas'));
279
+ return;
269
280
  }
281
+ const targetVersion = version || latest.version;
270
282
  // Get install config to determine type
271
283
  const installConfig = await (0, client_js_1.getInstallConfig)(namespace, name);
272
284
  if (installConfig.type === 'MCP_SERVER') {
@@ -274,7 +286,10 @@ exports.installCommand = new commander_1.Command('install')
274
286
  }
275
287
  else {
276
288
  // TOOL or DOMAIN — file-based installation
277
- await installToolOrDomain(namespace, name, targetVersion, installConfig);
289
+ await installToolOrDomain(namespace, name, targetVersion, {
290
+ ...installConfig,
291
+ tier: installConfig.tier || skillTier,
292
+ });
278
293
  }
279
294
  // Register install (best-effort)
280
295
  try {
@@ -182,7 +182,7 @@ exports.publishCommand = new commander_1.Command('publish')
182
182
  const spinner = (0, ora_1.default)(`Publicando ${chalk_1.default.bold(name)}${chalk_1.default.gray('@' + version)}...`).start();
183
183
  const files = readFilesRecursive(resolvedFolder, resolvedFolder);
184
184
  try {
185
- await (0, client_js_1.publishSkill)({
185
+ const published = await (0, client_js_1.publishSkill)({
186
186
  namespace,
187
187
  name,
188
188
  description,
@@ -194,6 +194,9 @@ exports.publishCommand = new commander_1.Command('publish')
194
194
  tier,
195
195
  });
196
196
  spinner.succeed(chalk_1.default.green(`Skill publicado: ${namespace}/${name}`));
197
+ if (published?.moderation?.status === 'pending_review') {
198
+ console.log(chalk_1.default.yellow('Submitted for review, pending approval.'));
199
+ }
197
200
  }
198
201
  catch (error) {
199
202
  if (axios_1.default.isAxiosError(error) && error.response?.status === 409) {
@@ -207,8 +210,11 @@ exports.publishCommand = new commander_1.Command('publish')
207
210
  return;
208
211
  }
209
212
  const versionSpinner = (0, ora_1.default)(`Publicando versión ${version}...`).start();
210
- await (0, client_js_1.publishVersion)(namespace, name, { version, files });
213
+ const publishedVersion = await (0, client_js_1.publishVersion)(namespace, name, { version, files });
211
214
  versionSpinner.succeed(chalk_1.default.green(`Versión ${version} publicada: ${namespace}/${name}`));
215
+ if (publishedVersion?.moderation?.status === 'pending_review') {
216
+ console.log(chalk_1.default.yellow('Submitted for review, pending approval.'));
217
+ }
212
218
  }
213
219
  else {
214
220
  spinner.fail('Error al publicar');
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildPaidStubSkillMd = buildPaidStubSkillMd;
4
+ exports.buildPaidStubManifest = buildPaidStubManifest;
5
+ function buildPaidStubSkillMd(data) {
6
+ return `# ${data.namespace}/${data.name}
7
+
8
+ ## Resumen
9
+ Este skill se instala en modo remoto. El código fuente no se descarga localmente.
10
+
11
+ ## Cuándo usar
12
+ Usa este skill cuando necesites ejecutar sus capacidades desde el registry por API.
13
+
14
+ ## Ejemplos
15
+ - Autorizar acceso: \`POST ${data.authorizeEndpoint || '/v1/skills/{namespace}/{name}/authorize'}\`
16
+ - Ejecutar skill: \`POST ${data.executeEndpoint || '/v1/skills/{namespace}/{name}/execute'}\`
17
+
18
+ ## Notas
19
+ - Requiere suscripción activa para este tier (\`${data.tier}\`).
20
+ - La ejecución ocurre de forma remota por API.
21
+ `;
22
+ }
23
+ function buildPaidStubManifest(data) {
24
+ const manifest = {
25
+ namespace: data.namespace,
26
+ name: data.name,
27
+ tier: data.tier,
28
+ executionMode: 'remote',
29
+ remoteExecutionOnly: true,
30
+ authorizeEndpoint: data.authorizeEndpoint,
31
+ };
32
+ if (data.executeEndpoint) {
33
+ manifest.executeEndpoint = data.executeEndpoint;
34
+ }
35
+ return manifest;
36
+ }
@@ -0,0 +1,22 @@
1
+ module.exports = {
2
+ testEnvironment: 'node',
3
+ roots: ['<rootDir>/src'],
4
+ testMatch: ['**/*.test.js'],
5
+ moduleFileExtensions: ['ts', 'js', 'json'],
6
+ transform: {
7
+ '^.+\\.ts$': [
8
+ 'ts-jest',
9
+ {
10
+ tsconfig: {
11
+ module: 'commonjs',
12
+ target: 'es2022',
13
+ esModuleInterop: true,
14
+ },
15
+ },
16
+ ],
17
+ },
18
+ moduleNameMapper: {
19
+ '^(\\.{1,2}/.*)\\.js$': '$1',
20
+ },
21
+ clearMocks: true,
22
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-skills-cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "CLI tool for OpenClaw Skills Registry",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {
@@ -0,0 +1,35 @@
1
+ # Paid Remote-Only Stub Template
2
+
3
+ ## SKILL.md
4
+
5
+ ```md
6
+ # {{namespace}}/{{name}}
7
+
8
+ ## Resumen
9
+ Este skill se instala en modo remoto. El código fuente no se descarga localmente.
10
+
11
+ ## Cuándo usar
12
+ Usa este skill cuando necesites ejecutar sus capacidades desde el registry por API.
13
+
14
+ ## Ejemplos
15
+ - Autorizar acceso: `POST {{authorizeEndpoint}}`
16
+ - Ejecutar skill: `POST {{executeEndpoint}}`
17
+
18
+ ## Notas
19
+ - Requiere suscripción activa para este tier (`{{tier}}`).
20
+ - La ejecución ocurre de forma remota por API.
21
+ ```
22
+
23
+ ## manifest.json
24
+
25
+ ```json
26
+ {
27
+ "namespace": "{{namespace}}",
28
+ "name": "{{name}}",
29
+ "tier": "{{tier}}",
30
+ "executionMode": "remote",
31
+ "remoteExecutionOnly": true,
32
+ "authorizeEndpoint": "{{authorizeEndpoint}}",
33
+ "executeEndpoint": "{{executeEndpoint}}"
34
+ }
35
+ ```