clawlabor 1.11.1 → 1.11.2
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 +5 -3
- package/README.md +41 -25
- package/SECURITY.md +2 -2
- package/SKILL.md +3 -3
- package/bin/install.js +184 -88
- package/package.json +1 -1
- package/runtime/cli.js +7 -0
- package/runtime/commands/command-install.js +22 -0
- package/runtime/commands/core.js +2 -0
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 (
|
|
13
|
-
|
|
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:
|
|
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
|
|
15
|
+
### Via npm (recommended — auto-updating symlinks)
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
#
|
|
19
|
-
|
|
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
|
-
#
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
169
|
+
npx --yes clawlabor install
|
|
154
170
|
|
|
155
171
|
# Or force a target when auto-detection is wrong:
|
|
156
|
-
# npx --yes
|
|
157
|
-
# npx --yes
|
|
158
|
-
# npx --yes
|
|
159
|
-
# npx --yes
|
|
160
|
-
# npx --yes
|
|
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
|
-
|
|
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.
|
|
4
|
+
version: "1.11.2"
|
|
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
|
|
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
|
|
14
|
-
* npx --yes
|
|
15
|
-
* npx --yes
|
|
16
|
-
* npx --yes
|
|
17
|
-
* npx --yes
|
|
18
|
-
* npx --yes
|
|
19
|
-
* npx --yes
|
|
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,9 +62,6 @@ 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
|
|
|
@@ -99,46 +105,93 @@ function copyDirectoryRecursive(srcDir, destDir) {
|
|
|
99
105
|
}
|
|
100
106
|
}
|
|
101
107
|
|
|
108
|
+
function resolveNpmRoot() {
|
|
109
|
+
// Test escape hatch so unit tests can avoid running real npm and avoid touching
|
|
110
|
+
// the user's machine.
|
|
111
|
+
if (process.env.CLAWLABOR_NPM_ROOT_OVERRIDE) {
|
|
112
|
+
return process.env.CLAWLABOR_NPM_ROOT_OVERRIDE;
|
|
113
|
+
}
|
|
114
|
+
const result = spawnSync("npm", ["root", "-g"], {
|
|
115
|
+
encoding: "utf8",
|
|
116
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
117
|
+
});
|
|
118
|
+
if (result.status !== 0 || !result.stdout) return null;
|
|
119
|
+
return result.stdout.trim() || null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function canonicalSkillDir() {
|
|
123
|
+
const npmRoot = resolveNpmRoot();
|
|
124
|
+
if (!npmRoot) return null;
|
|
125
|
+
const candidate = path.join(npmRoot, SKILL_NAME);
|
|
126
|
+
return fs.existsSync(candidate) ? candidate : null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function safeLstat(p) {
|
|
130
|
+
try {
|
|
131
|
+
return fs.lstatSync(p);
|
|
132
|
+
} catch (err) {
|
|
133
|
+
if (err.code === "ENOENT") return null;
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function symlinkTarget(target, sourceDir) {
|
|
139
|
+
// Replace whatever's at `target` (file / dir / existing symlink) with a fresh
|
|
140
|
+
// symlink → sourceDir. Returns { ok, error? }. Windows or hardened sandboxes
|
|
141
|
+
// may refuse symlink creation; caller falls back to copy mode.
|
|
142
|
+
const stat = safeLstat(target);
|
|
143
|
+
if (stat) {
|
|
144
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
148
|
+
fs.symlinkSync(sourceDir, target, "dir");
|
|
149
|
+
return { ok: true };
|
|
150
|
+
} catch (err) {
|
|
151
|
+
return { ok: false, error: err.message };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
102
155
|
function removeSkillDir(targetDir) {
|
|
103
|
-
if (fs.existsSync(targetDir)) {
|
|
156
|
+
if (fs.existsSync(targetDir) || safeLstat(targetDir)) {
|
|
104
157
|
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
105
158
|
return true;
|
|
106
159
|
}
|
|
107
160
|
return false;
|
|
108
161
|
}
|
|
109
162
|
|
|
110
|
-
function detectPlatforms() {
|
|
163
|
+
function detectPlatforms(home) {
|
|
111
164
|
const detected = [];
|
|
112
|
-
if (fs.existsSync(path.join(
|
|
113
|
-
if (fs.existsSync(path.join(
|
|
114
|
-
if (fs.existsSync(path.join(
|
|
115
|
-
if (fs.existsSync(path.join(
|
|
165
|
+
if (fs.existsSync(path.join(home, ".claude"))) detected.push("claude");
|
|
166
|
+
if (fs.existsSync(path.join(home, ".openclaw"))) detected.push("openclaw");
|
|
167
|
+
if (fs.existsSync(path.join(home, ".codex"))) detected.push("codex");
|
|
168
|
+
if (fs.existsSync(path.join(home, ".hermes"))) detected.push("hermes");
|
|
116
169
|
// If none detected, default to claude
|
|
117
170
|
if (detected.length === 0) detected.push("claude");
|
|
118
171
|
return detected;
|
|
119
172
|
}
|
|
120
173
|
|
|
121
|
-
function selectedPlatformFlags() {
|
|
174
|
+
function selectedPlatformFlags(flags) {
|
|
122
175
|
return PLATFORM_FLAGS.filter((name) => flags.has(name));
|
|
123
176
|
}
|
|
124
177
|
|
|
125
|
-
function targetFor(platform, projectMode
|
|
178
|
+
function targetFor(platform, projectMode, platforms, projectPlatforms) {
|
|
126
179
|
return {
|
|
127
180
|
name: projectMode ? `project:${platform}` : platform,
|
|
128
|
-
dir: projectMode ?
|
|
181
|
+
dir: projectMode ? projectPlatforms[platform] : platforms[platform],
|
|
129
182
|
};
|
|
130
183
|
}
|
|
131
184
|
|
|
132
|
-
function selectedTargets() {
|
|
133
|
-
const selected = selectedPlatformFlags();
|
|
185
|
+
function selectedTargets(flags, platforms, projectPlatforms, home) {
|
|
186
|
+
const selected = selectedPlatformFlags(flags);
|
|
134
187
|
if (flags.has("project")) {
|
|
135
|
-
const
|
|
136
|
-
return
|
|
188
|
+
const list = selected.length > 0 ? selected : PLATFORM_FLAGS;
|
|
189
|
+
return list.map((platform) => targetFor(platform, true, platforms, projectPlatforms));
|
|
137
190
|
}
|
|
138
191
|
if (selected.length > 0) {
|
|
139
|
-
return selected.map((platform) => targetFor(platform, false));
|
|
192
|
+
return selected.map((platform) => targetFor(platform, false, platforms, projectPlatforms));
|
|
140
193
|
}
|
|
141
|
-
return detectPlatforms().map((platform) => targetFor(platform, false));
|
|
194
|
+
return detectPlatforms(home).map((platform) => targetFor(platform, false, platforms, projectPlatforms));
|
|
142
195
|
}
|
|
143
196
|
|
|
144
197
|
function commandAvailable(command, args = ["--version"]) {
|
|
@@ -164,21 +217,29 @@ function dependencyHints() {
|
|
|
164
217
|
|
|
165
218
|
// --- Main ---
|
|
166
219
|
|
|
167
|
-
|
|
168
|
-
|
|
220
|
+
function runInstaller(rawArgs = process.argv.slice(2)) {
|
|
221
|
+
const flags = new Set(rawArgs.map((a) => a.replace(/^--/, "")));
|
|
222
|
+
const home = resolveHome();
|
|
223
|
+
const platforms = platformsFor(home);
|
|
224
|
+
const projectPlatforms = projectPlatformsFor(process.cwd());
|
|
225
|
+
|
|
226
|
+
if (flags.has("help") || flags.has("h")) {
|
|
227
|
+
console.log(`
|
|
169
228
|
ClawLabor Skill Installer
|
|
170
229
|
|
|
171
230
|
Usage:
|
|
172
|
-
npx --yes
|
|
173
|
-
npx --yes
|
|
174
|
-
npx --yes
|
|
175
|
-
npx --yes
|
|
176
|
-
npx --yes
|
|
177
|
-
npx --yes
|
|
178
|
-
npx --yes
|
|
179
|
-
|
|
180
|
-
npx --yes
|
|
181
|
-
|
|
231
|
+
npx --yes clawlabor install Install for all detected platforms
|
|
232
|
+
npx --yes clawlabor install --claude Install for Claude Code only
|
|
233
|
+
npx --yes clawlabor install --openclaw Install for OpenClaw only
|
|
234
|
+
npx --yes clawlabor install --codex Install for Codex CLI only
|
|
235
|
+
npx --yes clawlabor install --hermes Install for Hermes only
|
|
236
|
+
npx --yes clawlabor install --project Install in current project's .claude/.openclaw/.codex/.hermes skill dirs
|
|
237
|
+
npx --yes clawlabor install --project --codex Install in current project's .codex/skills/ only
|
|
238
|
+
npx --yes clawlabor install --uninstall Remove from all platforms
|
|
239
|
+
npx --yes clawlabor install --help Show this help
|
|
240
|
+
|
|
241
|
+
(Legacy GitHub installer remains supported via:
|
|
242
|
+
npx --yes github:Reinforce-Omega/clawlabor-skill [...flags])
|
|
182
243
|
|
|
183
244
|
After installation, bootstrap credentials:
|
|
184
245
|
clawlabor bootstrap
|
|
@@ -190,46 +251,71 @@ If clawlabor is not on PATH:
|
|
|
190
251
|
Docs:
|
|
191
252
|
${DOCS_URL}
|
|
192
253
|
`);
|
|
193
|
-
|
|
194
|
-
}
|
|
254
|
+
return { action: "help", code: 0 };
|
|
255
|
+
}
|
|
195
256
|
|
|
196
|
-
if (flags.has("uninstall")) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
257
|
+
if (flags.has("uninstall")) {
|
|
258
|
+
console.log("Uninstalling ClawLabor skill...\n");
|
|
259
|
+
const removed = [];
|
|
260
|
+
for (const [platform, dir] of Object.entries(platforms)) {
|
|
261
|
+
if (removeSkillDir(dir)) {
|
|
262
|
+
console.log(` Removed from ${platform}: ${dir}`);
|
|
263
|
+
removed.push({ name: platform, dir });
|
|
264
|
+
}
|
|
203
265
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
266
|
+
for (const [platform, dir] of Object.entries(projectPlatforms)) {
|
|
267
|
+
if (removeSkillDir(dir)) {
|
|
268
|
+
console.log(` Removed from project:${platform}: ${dir}`);
|
|
269
|
+
removed.push({ name: `project:${platform}`, dir });
|
|
270
|
+
}
|
|
209
271
|
}
|
|
272
|
+
if (removed.length === 0) {
|
|
273
|
+
console.log(" No installations found.");
|
|
274
|
+
}
|
|
275
|
+
return { action: "uninstall", removed, code: 0 };
|
|
210
276
|
}
|
|
211
|
-
if (removed === 0) {
|
|
212
|
-
console.log(" No installations found.");
|
|
213
|
-
}
|
|
214
|
-
process.exit(0);
|
|
215
|
-
}
|
|
216
277
|
|
|
217
|
-
const targets = selectedTargets();
|
|
218
|
-
|
|
219
|
-
|
|
278
|
+
const targets = selectedTargets(flags, platforms, projectPlatforms, home);
|
|
279
|
+
const installed = [];
|
|
280
|
+
const failed = [];
|
|
281
|
+
|
|
282
|
+
// Symlink mode: when `npm i -g clawlabor` has installed the package globally,
|
|
283
|
+
// point every agent's skill dir at that one canonical location so
|
|
284
|
+
// `npm i -g clawlabor@latest` propagates to all agents automatically.
|
|
285
|
+
// `--copy` forces classic per-target file copies (useful on Windows without
|
|
286
|
+
// dev mode, or when an agent runtime can't follow symlinks).
|
|
287
|
+
const canonical = flags.has("copy") ? null : canonicalSkillDir();
|
|
288
|
+
const symlinkPreferred = canonical !== null;
|
|
289
|
+
|
|
290
|
+
if (symlinkPreferred) {
|
|
291
|
+
console.log(`Linking ClawLabor skill from ${canonical} ...\n`);
|
|
292
|
+
} else {
|
|
293
|
+
console.log("Installing ClawLabor skill...\n");
|
|
294
|
+
}
|
|
220
295
|
|
|
221
|
-
for (const { name, dir } of targets) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
296
|
+
for (const { name, dir } of targets) {
|
|
297
|
+
if (symlinkPreferred) {
|
|
298
|
+
const link = symlinkTarget(dir, canonical);
|
|
299
|
+
if (link.ok) {
|
|
300
|
+
console.log(` Linked ${name} -> ${canonical}`);
|
|
301
|
+
installed.push({ name, dir, mode: "link", target: canonical });
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
console.log(` Symlink failed for ${name} (${link.error}); falling back to copy`);
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
copySkillFiles(dir);
|
|
308
|
+
console.log(` Installed (copy) for ${name}: ${dir}`);
|
|
309
|
+
installed.push({ name, dir, mode: "copy" });
|
|
310
|
+
} catch (err) {
|
|
311
|
+
console.error(` Failed for ${name}: ${err.message}`);
|
|
312
|
+
failed.push({ name, dir, error: err.message });
|
|
313
|
+
}
|
|
227
314
|
}
|
|
228
|
-
}
|
|
229
315
|
|
|
230
|
-
const hints = dependencyHints();
|
|
316
|
+
const hints = dependencyHints();
|
|
231
317
|
|
|
232
|
-
console.log(`
|
|
318
|
+
console.log(`
|
|
233
319
|
|
|
234
320
|
ClawLabor skill installed!
|
|
235
321
|
|
|
@@ -257,8 +343,18 @@ console.log(`
|
|
|
257
343
|
|
|
258
344
|
`);
|
|
259
345
|
|
|
260
|
-
if (hints.length > 0) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
346
|
+
if (hints.length > 0) {
|
|
347
|
+
console.log("Optional dependency checks:\n");
|
|
348
|
+
console.log(hints.join("\n\n"));
|
|
349
|
+
console.log("");
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return { action: "install", installed, failed, hints, code: failed.length > 0 ? 1 : 0 };
|
|
264
353
|
}
|
|
354
|
+
|
|
355
|
+
if (require.main === module) {
|
|
356
|
+
const result = runInstaller();
|
|
357
|
+
process.exit(result.code || 0);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
module.exports = { runInstaller };
|
package/package.json
CHANGED
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 };
|
package/runtime/commands/core.js
CHANGED
|
@@ -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,
|