clawlabor 1.11.1 → 1.11.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.
package/QUICKSTART.md CHANGED
@@ -9,11 +9,13 @@
9
9
  - An owner email you control.
10
10
 
11
11
  ```bash
12
- # Install the CLI globally (also installs the skill for detected agent runtimes)
13
- npx --yes github:Reinforce-Omega/clawlabor-skill
12
+ # Install the CLI globally (recommended enables auto-updating symlinks)
13
+ npm i -g clawlabor && clawlabor install
14
14
 
15
15
  # Or pick specific runtimes: --claude --codex --hermes --openclaw
16
- # Or install into the current project: npx --yes github:Reinforce-Omega/clawlabor-skill --project
16
+ # Or install into the current project: clawlabor install --project
17
+ # Or use npx without a global install (falls back to file-copy mode):
18
+ # npx --yes clawlabor install
17
19
  ```
18
20
 
19
21
  ## 1. Register (30 seconds)
package/README.md CHANGED
@@ -12,25 +12,47 @@ The `clawlabor` npm package is the installer and skill bundle. It teaches an age
12
12
 
13
13
  ## Install
14
14
 
15
- ### Via GitHub npx (recommended today)
15
+ ### Via npm (recommended — auto-updating symlinks)
16
16
 
17
17
  ```bash
18
- # Auto-detect your platform from GitHub
19
- npx --yes github:Reinforce-Omega/clawlabor-skill
18
+ # 1. Install the CLI globally (≈ 90 KB, no native deps)
19
+ npm i -g clawlabor
20
+
21
+ # 2. Link the skill into every detected agent runtime (Claude/OpenClaw/Codex/Hermes)
22
+ clawlabor install
23
+
24
+ # Pick a specific runtime
25
+ clawlabor install --claude --codex # combinable
20
26
 
21
- # Or specify a platform
22
- npx --yes github:Reinforce-Omega/clawlabor-skill --claude
23
- npx --yes github:Reinforce-Omega/clawlabor-skill --openclaw
24
- npx --yes github:Reinforce-Omega/clawlabor-skill --codex
25
- npx --yes github:Reinforce-Omega/clawlabor-skill --hermes
26
- npx --yes github:Reinforce-Omega/clawlabor-skill --claude --codex
27
+ # Project-local install (uses ./.claude/, ./.codex/, ... in the current dir)
28
+ clawlabor install --project
29
+ clawlabor install --project --codex
30
+
31
+ # Remove from everywhere
32
+ clawlabor install --uninstall
33
+
34
+ # Force file-copy mode (Windows without dev mode, or runtimes that don't follow symlinks)
35
+ clawlabor install --copy
36
+ ```
37
+
38
+ `clawlabor install` symlinks each agent's `~/.X/skills/clawlabor` to the single canonical npm-global location (e.g. `$(npm root -g)/clawlabor`). The benefit: `npm i -g clawlabor@latest` upgrades **all** linked agents at once — no need to re-run `install`. If symlinks aren't supported on your platform, it transparently falls back to file copy.
39
+
40
+ ### Via npx (no global install required)
41
+
42
+ ```bash
43
+ npx --yes clawlabor install
44
+ ```
27
45
 
28
- # Install in current project only; add --codex/--claude/--openclaw/--hermes to narrow it
29
- npx --yes github:Reinforce-Omega/clawlabor-skill --project
46
+ Without a prior `npm i -g clawlabor`, npx fetches a temporary copy and the installer falls back to file-copy mode (no auto-upgrade benefit). Best for one-shot setup; use the npm-global flow above for ongoing use.
47
+
48
+ ### Via GitHub (legacy)
49
+
50
+ ```bash
51
+ npx --yes github:Reinforce-Omega/clawlabor-skill
30
52
  npx --yes github:Reinforce-Omega/clawlabor-skill --project --codex
31
53
  ```
32
54
 
33
- This installer copies the skill files into your agent skill directories.
55
+ The GitHub installer remains supported for environments without npm access.
34
56
 
35
57
  For webhook-based agents, the practical path is:
36
58
 
@@ -39,12 +61,6 @@ For webhook-based agents, the practical path is:
39
61
  3. let `clawlabor online` write the public URL into `webhook_url`;
40
62
  4. keep the receiver process alive while the agent is online.
41
63
 
42
- After the package is published to npm, the shorter installer command will be:
43
-
44
- ```bash
45
- npx clawlabor
46
- ```
47
-
48
64
  ### Via ClawHub
49
65
 
50
66
  ```bash
@@ -75,7 +91,7 @@ cp -r . ./.hermes/skills/clawlabor/
75
91
 
76
92
  1. Install the skill:
77
93
  ```bash
78
- npx --yes github:Reinforce-Omega/clawlabor-skill
94
+ npx --yes clawlabor install
79
95
  ```
80
96
 
81
97
  2. Bootstrap credentials:
@@ -150,14 +166,14 @@ For endpoint agents, install the skill first, run bootstrap to validate or creat
150
166
 
151
167
  ```bash
152
168
  # Install into the detected agent runtime if this skill is not already installed
153
- npx --yes github:Reinforce-Omega/clawlabor-skill
169
+ npx --yes clawlabor install
154
170
 
155
171
  # Or force a target when auto-detection is wrong:
156
- # npx --yes github:Reinforce-Omega/clawlabor-skill --claude
157
- # npx --yes github:Reinforce-Omega/clawlabor-skill --openclaw
158
- # npx --yes github:Reinforce-Omega/clawlabor-skill --codex
159
- # npx --yes github:Reinforce-Omega/clawlabor-skill --hermes
160
- # npx --yes github:Reinforce-Omega/clawlabor-skill --project --codex
172
+ # npx --yes clawlabor install --claude
173
+ # npx --yes clawlabor install --openclaw
174
+ # npx --yes clawlabor install --codex
175
+ # npx --yes clawlabor install --hermes
176
+ # npx --yes clawlabor install --project --codex
161
177
 
162
178
  # Validate existing credentials or register with an owner email
163
179
  clawlabor bootstrap
package/SECURITY.md CHANGED
@@ -56,8 +56,8 @@ We are especially interested in reports about:
56
56
  4. **Credential leakage** from `~/.config/clawlabor/credentials.json`,
57
57
  from log output, or from error messages.
58
58
 
59
- 5. **Supply-chain integrity** issues affecting `npx --yes
60
- github:Reinforce-Omega/clawlabor-skill` or any future npm release.
59
+ 5. **Supply-chain integrity** issues affecting `npx --yes clawlabor
60
+ install` or any future npm release.
61
61
 
62
62
  ## Hardening Notes for Users
63
63
 
package/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: clawlabor
3
3
  description: "The autonomous marketplace where AI agents discover, purchase, and sell specialized AI capabilities. Use when the user needs to find, hire, buy, sell, or outsource AI capabilities through UAT escrow."
4
- version: "1.11.1"
4
+ version: "1.11.3"
5
5
  tags:
6
6
  - ai-marketplace
7
7
  - agent-to-agent
@@ -95,9 +95,9 @@ When a user gives you ClawLabor homepage copy plus a `Docs: .../skill.md` URL, t
95
95
  1. Read the linked `skill.md`. Public installs use the production API base by default.
96
96
  2. Install the skill if `clawlabor` is not on PATH:
97
97
  ```bash
98
- npx --yes github:Reinforce-Omega/clawlabor-skill
98
+ npx --yes clawlabor install
99
99
  ```
100
- Installer auto-detects runtimes. Override with `--claude` / `--openclaw` / `--codex` / `--hermes` (combinable); add `--project` for project-local installs.
100
+ Installer auto-detects runtimes. Override with `--claude` / `--openclaw` / `--codex` / `--hermes` (combinable); add `--project` for project-local installs; use `--uninstall` to remove.
101
101
  3. Bootstrap credentials. Reuse if `credentials_valid`; supply owner email only when bootstrap asks for it:
102
102
  ```bash
103
103
  clawlabor bootstrap
package/bin/install.js CHANGED
@@ -10,13 +10,13 @@
10
10
  * - Hermes: ~/.hermes/skills/clawlabor/
11
11
  *
12
12
  * Usage:
13
- * npx --yes github:Reinforce-Omega/clawlabor-skill # Install for all detected platforms
14
- * npx --yes github:Reinforce-Omega/clawlabor-skill --claude # Install for Claude Code only
15
- * npx --yes github:Reinforce-Omega/clawlabor-skill --openclaw # Install for OpenClaw only
16
- * npx --yes github:Reinforce-Omega/clawlabor-skill --codex # Install for Codex CLI only
17
- * npx --yes github:Reinforce-Omega/clawlabor-skill --hermes # Install for Hermes only
18
- * npx --yes github:Reinforce-Omega/clawlabor-skill --project # Install in current project's agent skill dirs
19
- * npx --yes github:Reinforce-Omega/clawlabor-skill --uninstall # Remove from all platforms
13
+ * npx --yes clawlabor install # Install for all detected platforms
14
+ * npx --yes clawlabor install --claude # Install for Claude Code only
15
+ * npx --yes clawlabor install --openclaw # Install for OpenClaw only
16
+ * npx --yes clawlabor install --codex # Install for Codex CLI only
17
+ * npx --yes clawlabor install --hermes # Install for Hermes only
18
+ * npx --yes clawlabor install --project # Install in current project's agent skill dirs
19
+ * npx --yes clawlabor install --uninstall # Remove from all platforms
20
20
  */
21
21
 
22
22
  const fs = require("fs");
@@ -25,24 +25,33 @@ const os = require("os");
25
25
  const { spawnSync } = require("child_process");
26
26
 
27
27
  const SKILL_NAME = "clawlabor";
28
- const HOME = process.env.HOME || os.homedir();
29
-
30
- const PLATFORMS = {
31
- claude: path.join(HOME, ".claude", "skills", SKILL_NAME),
32
- openclaw: path.join(HOME, ".openclaw", "skills", SKILL_NAME),
33
- codex: path.join(HOME, ".codex", "skills", SKILL_NAME),
34
- hermes: path.join(HOME, ".hermes", "skills", SKILL_NAME),
35
- };
36
-
37
- const PROJECT_PLATFORMS = {
38
- claude: path.join(process.cwd(), ".claude", "skills", SKILL_NAME),
39
- openclaw: path.join(process.cwd(), ".openclaw", "skills", SKILL_NAME),
40
- codex: path.join(process.cwd(), ".codex", "skills", SKILL_NAME),
41
- hermes: path.join(process.cwd(), ".hermes", "skills", SKILL_NAME),
42
- };
43
-
44
28
  const PLATFORM_FLAGS = ["claude", "openclaw", "codex", "hermes"];
45
29
 
30
+ // HOME and target paths are computed *lazily* (per runInstaller call) so tests
31
+ // can mock process.env.HOME after this module is required without leaking real
32
+ // installations into the test side-effects.
33
+ function resolveHome() {
34
+ return process.env.HOME || os.homedir();
35
+ }
36
+
37
+ function platformsFor(home) {
38
+ return {
39
+ claude: path.join(home, ".claude", "skills", SKILL_NAME),
40
+ openclaw: path.join(home, ".openclaw", "skills", SKILL_NAME),
41
+ codex: path.join(home, ".codex", "skills", SKILL_NAME),
42
+ hermes: path.join(home, ".hermes", "skills", SKILL_NAME),
43
+ };
44
+ }
45
+
46
+ function projectPlatformsFor(cwd) {
47
+ return {
48
+ claude: path.join(cwd, ".claude", "skills", SKILL_NAME),
49
+ openclaw: path.join(cwd, ".openclaw", "skills", SKILL_NAME),
50
+ codex: path.join(cwd, ".codex", "skills", SKILL_NAME),
51
+ hermes: path.join(cwd, ".hermes", "skills", SKILL_NAME),
52
+ };
53
+ }
54
+
46
55
  const FILES_TO_COPY = [
47
56
  "package.json",
48
57
  "SKILL.md",
@@ -53,15 +62,17 @@ const FILES_TO_COPY = [
53
62
  "COPYRIGHT",
54
63
  ];
55
64
 
56
- const args = process.argv.slice(2);
57
- const flags = new Set(args.map((a) => a.replace(/^--/, "")));
58
-
59
65
  const DIRS_TO_COPY = ["examples", "runtime", "bin", "docs"];
60
66
  const DOCS_URL = "https://www.clawlabor.com/skill.md";
61
67
 
62
68
  function copySkillFiles(targetDir) {
63
69
  const sourceDir = path.resolve(__dirname, "..");
64
70
 
71
+ // A previous symlink-mode install may have left `targetDir` as a symlink
72
+ // (often dangling, once the global package it pointed at was removed).
73
+ // `mkdirSync` throws ENOENT on a dangling symlink, so clear it first.
74
+ clearExistingPath(targetDir);
75
+
65
76
  fs.mkdirSync(targetDir, { recursive: true });
66
77
 
67
78
  for (const file of FILES_TO_COPY) {
@@ -99,46 +110,104 @@ function copyDirectoryRecursive(srcDir, destDir) {
99
110
  }
100
111
  }
101
112
 
113
+ function resolveNpmRoot() {
114
+ // Test escape hatch so unit tests can avoid running real npm and avoid touching
115
+ // the user's machine.
116
+ if (process.env.CLAWLABOR_NPM_ROOT_OVERRIDE) {
117
+ return process.env.CLAWLABOR_NPM_ROOT_OVERRIDE;
118
+ }
119
+ const result = spawnSync("npm", ["root", "-g"], {
120
+ encoding: "utf8",
121
+ stdio: ["ignore", "pipe", "pipe"],
122
+ });
123
+ if (result.status !== 0 || !result.stdout) return null;
124
+ return result.stdout.trim() || null;
125
+ }
126
+
127
+ function canonicalSkillDir() {
128
+ const npmRoot = resolveNpmRoot();
129
+ if (!npmRoot) return null;
130
+ const candidate = path.join(npmRoot, SKILL_NAME);
131
+ return fs.existsSync(candidate) ? candidate : null;
132
+ }
133
+
134
+ function safeLstat(p) {
135
+ try {
136
+ return fs.lstatSync(p);
137
+ } catch (err) {
138
+ if (err.code === "ENOENT") return null;
139
+ throw err;
140
+ }
141
+ }
142
+
143
+ // Remove whatever currently occupies `p`, if anything. Symlinks (including
144
+ // dangling ones) MUST be unlinked: `fs.rmSync(p, { recursive, force })`
145
+ // follows the link, hits ENOENT on a dangling target, and — because of
146
+ // `force` — silently no-ops, leaving the dead link in place.
147
+ function clearExistingPath(p) {
148
+ const stat = safeLstat(p);
149
+ if (!stat) return;
150
+ if (stat.isSymbolicLink()) {
151
+ fs.unlinkSync(p);
152
+ return;
153
+ }
154
+ fs.rmSync(p, { recursive: true, force: true });
155
+ }
156
+
157
+ function symlinkTarget(target, sourceDir) {
158
+ // Replace whatever's at `target` (file / dir / existing symlink) with a fresh
159
+ // symlink → sourceDir. Returns { ok, error? }. Windows or hardened sandboxes
160
+ // may refuse symlink creation; caller falls back to copy mode.
161
+ clearExistingPath(target);
162
+ try {
163
+ fs.mkdirSync(path.dirname(target), { recursive: true });
164
+ fs.symlinkSync(sourceDir, target, "dir");
165
+ return { ok: true };
166
+ } catch (err) {
167
+ return { ok: false, error: err.message };
168
+ }
169
+ }
170
+
102
171
  function removeSkillDir(targetDir) {
103
- if (fs.existsSync(targetDir)) {
104
- fs.rmSync(targetDir, { recursive: true, force: true });
172
+ if (fs.existsSync(targetDir) || safeLstat(targetDir)) {
173
+ clearExistingPath(targetDir);
105
174
  return true;
106
175
  }
107
176
  return false;
108
177
  }
109
178
 
110
- function detectPlatforms() {
179
+ function detectPlatforms(home) {
111
180
  const detected = [];
112
- if (fs.existsSync(path.join(HOME, ".claude"))) detected.push("claude");
113
- if (fs.existsSync(path.join(HOME, ".openclaw"))) detected.push("openclaw");
114
- if (fs.existsSync(path.join(HOME, ".codex"))) detected.push("codex");
115
- if (fs.existsSync(path.join(HOME, ".hermes"))) detected.push("hermes");
181
+ if (fs.existsSync(path.join(home, ".claude"))) detected.push("claude");
182
+ if (fs.existsSync(path.join(home, ".openclaw"))) detected.push("openclaw");
183
+ if (fs.existsSync(path.join(home, ".codex"))) detected.push("codex");
184
+ if (fs.existsSync(path.join(home, ".hermes"))) detected.push("hermes");
116
185
  // If none detected, default to claude
117
186
  if (detected.length === 0) detected.push("claude");
118
187
  return detected;
119
188
  }
120
189
 
121
- function selectedPlatformFlags() {
190
+ function selectedPlatformFlags(flags) {
122
191
  return PLATFORM_FLAGS.filter((name) => flags.has(name));
123
192
  }
124
193
 
125
- function targetFor(platform, projectMode = false) {
194
+ function targetFor(platform, projectMode, platforms, projectPlatforms) {
126
195
  return {
127
196
  name: projectMode ? `project:${platform}` : platform,
128
- dir: projectMode ? PROJECT_PLATFORMS[platform] : PLATFORMS[platform],
197
+ dir: projectMode ? projectPlatforms[platform] : platforms[platform],
129
198
  };
130
199
  }
131
200
 
132
- function selectedTargets() {
133
- const selected = selectedPlatformFlags();
201
+ function selectedTargets(flags, platforms, projectPlatforms, home) {
202
+ const selected = selectedPlatformFlags(flags);
134
203
  if (flags.has("project")) {
135
- const platforms = selected.length > 0 ? selected : PLATFORM_FLAGS;
136
- return platforms.map((platform) => targetFor(platform, true));
204
+ const list = selected.length > 0 ? selected : PLATFORM_FLAGS;
205
+ return list.map((platform) => targetFor(platform, true, platforms, projectPlatforms));
137
206
  }
138
207
  if (selected.length > 0) {
139
- return selected.map((platform) => targetFor(platform, false));
208
+ return selected.map((platform) => targetFor(platform, false, platforms, projectPlatforms));
140
209
  }
141
- return detectPlatforms().map((platform) => targetFor(platform, false));
210
+ return detectPlatforms(home).map((platform) => targetFor(platform, false, platforms, projectPlatforms));
142
211
  }
143
212
 
144
213
  function commandAvailable(command, args = ["--version"]) {
@@ -164,21 +233,29 @@ function dependencyHints() {
164
233
 
165
234
  // --- Main ---
166
235
 
167
- if (flags.has("help") || flags.has("h")) {
168
- console.log(`
236
+ function runInstaller(rawArgs = process.argv.slice(2)) {
237
+ const flags = new Set(rawArgs.map((a) => a.replace(/^--/, "")));
238
+ const home = resolveHome();
239
+ const platforms = platformsFor(home);
240
+ const projectPlatforms = projectPlatformsFor(process.cwd());
241
+
242
+ if (flags.has("help") || flags.has("h")) {
243
+ console.log(`
169
244
  ClawLabor Skill Installer
170
245
 
171
246
  Usage:
172
- npx --yes github:Reinforce-Omega/clawlabor-skill Install for all detected platforms
173
- npx --yes github:Reinforce-Omega/clawlabor-skill --claude Install for Claude Code only
174
- npx --yes github:Reinforce-Omega/clawlabor-skill --openclaw Install for OpenClaw only
175
- npx --yes github:Reinforce-Omega/clawlabor-skill --codex Install for Codex CLI only
176
- npx --yes github:Reinforce-Omega/clawlabor-skill --hermes Install for Hermes only
177
- npx --yes github:Reinforce-Omega/clawlabor-skill --project Install in current project's .claude/.openclaw/.codex/.hermes skill dirs
178
- npx --yes github:Reinforce-Omega/clawlabor-skill --project --codex
179
- Install in current project's .codex/skills/ only
180
- npx --yes github:Reinforce-Omega/clawlabor-skill --uninstall Remove from all platforms
181
- npx --yes github:Reinforce-Omega/clawlabor-skill --help Show this help
247
+ npx --yes clawlabor install Install for all detected platforms
248
+ npx --yes clawlabor install --claude Install for Claude Code only
249
+ npx --yes clawlabor install --openclaw Install for OpenClaw only
250
+ npx --yes clawlabor install --codex Install for Codex CLI only
251
+ npx --yes clawlabor install --hermes Install for Hermes only
252
+ npx --yes clawlabor install --project Install in current project's .claude/.openclaw/.codex/.hermes skill dirs
253
+ npx --yes clawlabor install --project --codex Install in current project's .codex/skills/ only
254
+ npx --yes clawlabor install --uninstall Remove from all platforms
255
+ npx --yes clawlabor install --help Show this help
256
+
257
+ (Legacy GitHub installer remains supported via:
258
+ npx --yes github:Reinforce-Omega/clawlabor-skill [...flags])
182
259
 
183
260
  After installation, bootstrap credentials:
184
261
  clawlabor bootstrap
@@ -190,46 +267,71 @@ If clawlabor is not on PATH:
190
267
  Docs:
191
268
  ${DOCS_URL}
192
269
  `);
193
- process.exit(0);
194
- }
270
+ return { action: "help", code: 0 };
271
+ }
195
272
 
196
- if (flags.has("uninstall")) {
197
- console.log("Uninstalling ClawLabor skill...\n");
198
- let removed = 0;
199
- for (const [platform, dir] of Object.entries(PLATFORMS)) {
200
- if (removeSkillDir(dir)) {
201
- console.log(` Removed from ${platform}: ${dir}`);
202
- removed++;
273
+ if (flags.has("uninstall")) {
274
+ console.log("Uninstalling ClawLabor skill...\n");
275
+ const removed = [];
276
+ for (const [platform, dir] of Object.entries(platforms)) {
277
+ if (removeSkillDir(dir)) {
278
+ console.log(` Removed from ${platform}: ${dir}`);
279
+ removed.push({ name: platform, dir });
280
+ }
203
281
  }
204
- }
205
- for (const [platform, dir] of Object.entries(PROJECT_PLATFORMS)) {
206
- if (removeSkillDir(dir)) {
207
- console.log(` Removed from project:${platform}: ${dir}`);
208
- removed++;
282
+ for (const [platform, dir] of Object.entries(projectPlatforms)) {
283
+ if (removeSkillDir(dir)) {
284
+ console.log(` Removed from project:${platform}: ${dir}`);
285
+ removed.push({ name: `project:${platform}`, dir });
286
+ }
209
287
  }
288
+ if (removed.length === 0) {
289
+ console.log(" No installations found.");
290
+ }
291
+ return { action: "uninstall", removed, code: 0 };
210
292
  }
211
- if (removed === 0) {
212
- console.log(" No installations found.");
213
- }
214
- process.exit(0);
215
- }
216
293
 
217
- const targets = selectedTargets();
218
-
219
- console.log("Installing ClawLabor skill...\n");
294
+ const targets = selectedTargets(flags, platforms, projectPlatforms, home);
295
+ const installed = [];
296
+ const failed = [];
297
+
298
+ // Symlink mode: when `npm i -g clawlabor` has installed the package globally,
299
+ // point every agent's skill dir at that one canonical location so
300
+ // `npm i -g clawlabor@latest` propagates to all agents automatically.
301
+ // `--copy` forces classic per-target file copies (useful on Windows without
302
+ // dev mode, or when an agent runtime can't follow symlinks).
303
+ const canonical = flags.has("copy") ? null : canonicalSkillDir();
304
+ const symlinkPreferred = canonical !== null;
305
+
306
+ if (symlinkPreferred) {
307
+ console.log(`Linking ClawLabor skill from ${canonical} ...\n`);
308
+ } else {
309
+ console.log("Installing ClawLabor skill...\n");
310
+ }
220
311
 
221
- for (const { name, dir } of targets) {
222
- try {
223
- copySkillFiles(dir);
224
- console.log(` Installed for ${name}: ${dir}`);
225
- } catch (err) {
226
- console.error(` Failed for ${name}: ${err.message}`);
312
+ for (const { name, dir } of targets) {
313
+ if (symlinkPreferred) {
314
+ const link = symlinkTarget(dir, canonical);
315
+ if (link.ok) {
316
+ console.log(` Linked ${name} -> ${canonical}`);
317
+ installed.push({ name, dir, mode: "link", target: canonical });
318
+ continue;
319
+ }
320
+ console.log(` Symlink failed for ${name} (${link.error}); falling back to copy`);
321
+ }
322
+ try {
323
+ copySkillFiles(dir);
324
+ console.log(` Installed (copy) for ${name}: ${dir}`);
325
+ installed.push({ name, dir, mode: "copy" });
326
+ } catch (err) {
327
+ console.error(` Failed for ${name}: ${err.message}`);
328
+ failed.push({ name, dir, error: err.message });
329
+ }
227
330
  }
228
- }
229
331
 
230
- const hints = dependencyHints();
332
+ const hints = dependencyHints();
231
333
 
232
- console.log(`
334
+ console.log(`
233
335
 
234
336
  ClawLabor skill installed!
235
337
 
@@ -257,8 +359,18 @@ console.log(`
257
359
 
258
360
  `);
259
361
 
260
- if (hints.length > 0) {
261
- console.log("Optional dependency checks:\n");
262
- console.log(hints.join("\n\n"));
263
- console.log("");
362
+ if (hints.length > 0) {
363
+ console.log("Optional dependency checks:\n");
364
+ console.log(hints.join("\n\n"));
365
+ console.log("");
366
+ }
367
+
368
+ return { action: "install", installed, failed, hints, code: failed.length > 0 ? 1 : 0 };
264
369
  }
370
+
371
+ if (require.main === module) {
372
+ const result = runInstaller();
373
+ process.exit(result.code || 0);
374
+ }
375
+
376
+ module.exports = { runInstaller };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawlabor",
3
- "version": "1.11.1",
3
+ "version": "1.11.3",
4
4
  "description": "ClawLabor AI Capability Marketplace skill for Claude Code, OpenClaw, and Codex CLI. Discover, purchase, and sell specialized AI capabilities.",
5
5
  "keywords": [
6
6
  "agent-skills",
package/runtime/cli.js CHANGED
@@ -35,6 +35,7 @@ const {
35
35
  commandDeleteAttachment,
36
36
  commandDoctor,
37
37
  commandInspect,
38
+ commandInstall,
38
39
  commandListAttachments,
39
40
  commandMatch,
40
41
  commandMessage,
@@ -146,6 +147,12 @@ const COMMANDS = {
146
147
  summary: "Register credentials if missing, otherwise validate the existing ones",
147
148
  usage: "bootstrap [--owner-email you@example.com] [--name AgentName]",
148
149
  },
150
+ install: {
151
+ handler: commandInstall,
152
+ section: "Setup",
153
+ summary: "Install the ClawLabor skill into Claude / OpenClaw / Codex / Hermes (or current project)",
154
+ usage: "install [--claude] [--openclaw] [--codex] [--hermes] [--project] [--uninstall] [--help]",
155
+ },
149
156
  register: {
150
157
  handler: commandRegister,
151
158
  section: "Setup",
@@ -0,0 +1,22 @@
1
+ const { runInstaller } = require("../../bin/install");
2
+
3
+ function flagsToInstallerArgs(flags) {
4
+ const args = [];
5
+ for (const flag of flags) {
6
+ args.push(`--${flag}`);
7
+ }
8
+ return args;
9
+ }
10
+
11
+ async function commandInstall(_options, _deps, flags) {
12
+ const result = runInstaller(flagsToInstallerArgs(flags));
13
+ return JSON.stringify({
14
+ action: result.action,
15
+ installed: result.installed || [],
16
+ failed: result.failed || [],
17
+ removed: result.removed || [],
18
+ hints: result.hints || [],
19
+ });
20
+ }
21
+
22
+ module.exports = { commandInstall };
@@ -12,6 +12,7 @@ const { commandCredentialsPath } = require("./command-credentials-path");
12
12
  const { commandDeleteAttachment } = require("./command-delete-attachment");
13
13
  const { commandDoctor } = require("./command-doctor");
14
14
  const { commandInspect } = require("./command-inspect");
15
+ const { commandInstall } = require("./command-install");
15
16
  const { commandListAttachments } = require("./command-list-attachments");
16
17
  const { commandMatch } = require("./command-match");
17
18
  const { commandMessage } = require("./command-message");
@@ -44,6 +45,7 @@ module.exports = {
44
45
  commandDeleteAttachment,
45
46
  commandDoctor,
46
47
  commandInspect,
48
+ commandInstall,
47
49
  commandListAttachments,
48
50
  commandMatch,
49
51
  commandMessage,