@web42/cli 0.2.7 → 0.2.9
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/dist/commands/search.js +20 -15
- package/dist/commands/send.js +75 -41
- package/dist/commands/serve.d.ts +1 -1
- package/dist/commands/serve.js +160 -114
- package/dist/index.js +1 -19
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/commands/config.d.ts +0 -2
- package/dist/commands/config.js +0 -27
- package/dist/commands/init.d.ts +0 -2
- package/dist/commands/init.js +0 -451
- package/dist/commands/install.d.ts +0 -3
- package/dist/commands/install.js +0 -231
- package/dist/commands/list.d.ts +0 -3
- package/dist/commands/list.js +0 -22
- package/dist/commands/pack.d.ts +0 -2
- package/dist/commands/pack.js +0 -210
- package/dist/commands/pull.d.ts +0 -2
- package/dist/commands/pull.js +0 -202
- package/dist/commands/push.d.ts +0 -2
- package/dist/commands/push.js +0 -374
- package/dist/commands/remix.d.ts +0 -2
- package/dist/commands/remix.js +0 -49
- package/dist/commands/sync.d.ts +0 -2
- package/dist/commands/sync.js +0 -98
- package/dist/commands/uninstall.d.ts +0 -3
- package/dist/commands/uninstall.js +0 -54
- package/dist/commands/update.d.ts +0 -3
- package/dist/commands/update.js +0 -59
- package/dist/platforms/base.d.ts +0 -82
- package/dist/platforms/base.js +0 -1
- package/dist/platforms/claude/__tests__/adapter.test.d.ts +0 -1
- package/dist/platforms/claude/__tests__/adapter.test.js +0 -257
- package/dist/platforms/claude/__tests__/security.test.d.ts +0 -1
- package/dist/platforms/claude/__tests__/security.test.js +0 -166
- package/dist/platforms/claude/adapter.d.ts +0 -34
- package/dist/platforms/claude/adapter.js +0 -525
- package/dist/platforms/claude/security.d.ts +0 -15
- package/dist/platforms/claude/security.js +0 -67
- package/dist/platforms/claude/templates.d.ts +0 -5
- package/dist/platforms/claude/templates.js +0 -22
- package/dist/platforms/openclaw/adapter.d.ts +0 -12
- package/dist/platforms/openclaw/adapter.js +0 -476
- package/dist/platforms/openclaw/templates.d.ts +0 -7
- package/dist/platforms/openclaw/templates.js +0 -369
- package/dist/platforms/registry.d.ts +0 -6
- package/dist/platforms/registry.js +0 -32
- package/dist/types/sync.d.ts +0 -74
- package/dist/types/sync.js +0 -7
- package/dist/utils/bundled-skills.d.ts +0 -6
- package/dist/utils/bundled-skills.js +0 -29
- package/dist/utils/secrets.d.ts +0 -32
- package/dist/utils/secrets.js +0 -118
- package/dist/utils/skill.d.ts +0 -6
- package/dist/utils/skill.js +0 -42
- package/dist/utils/sync.d.ts +0 -14
- package/dist/utils/sync.js +0 -242
package/dist/commands/init.js
DELETED
|
@@ -1,451 +0,0 @@
|
|
|
1
|
-
import { writeFileSync, mkdirSync, existsSync, readdirSync, readFileSync, } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
3
|
-
import { Command } from "commander";
|
|
4
|
-
import chalk from "chalk";
|
|
5
|
-
import inquirer from "inquirer";
|
|
6
|
-
import { requireAuth } from "../utils/config.js";
|
|
7
|
-
import { parseSkillMd } from "../utils/skill.js";
|
|
8
|
-
import { listBundledSkills, copySkillToWorkspace } from "../utils/bundled-skills.js";
|
|
9
|
-
import { resolvePlatform, listPlatforms } from "../platforms/registry.js";
|
|
10
|
-
import { writeMarketplace, writeResourcesMeta } from "../utils/sync.js";
|
|
11
|
-
import { DEFAULT_MARKETPLACE } from "../types/sync.js";
|
|
12
|
-
import { AGENTS_MD, IDENTITY_MD, SOUL_MD, TOOLS_MD, USER_MD, HEARTBEAT_MD, INIT_BOOTSTRAP_MD, } from "../platforms/openclaw/templates.js";
|
|
13
|
-
function detectWorkspaceSkills(cwd) {
|
|
14
|
-
const skillsDir = join(cwd, "skills");
|
|
15
|
-
if (!existsSync(skillsDir))
|
|
16
|
-
return [];
|
|
17
|
-
const skills = [];
|
|
18
|
-
try {
|
|
19
|
-
const entries = readdirSync(skillsDir, { withFileTypes: true });
|
|
20
|
-
for (const entry of entries) {
|
|
21
|
-
if (entry.isDirectory()) {
|
|
22
|
-
const skillMd = join(skillsDir, entry.name, "SKILL.md");
|
|
23
|
-
if (existsSync(skillMd)) {
|
|
24
|
-
const content = readFileSync(skillMd, "utf-8");
|
|
25
|
-
const parsed = parseSkillMd(content, entry.name);
|
|
26
|
-
if (!parsed.internal) {
|
|
27
|
-
skills.push({ name: parsed.name, description: parsed.description });
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// ignore read errors
|
|
35
|
-
}
|
|
36
|
-
return skills.sort((a, b) => a.name.localeCompare(b.name));
|
|
37
|
-
}
|
|
38
|
-
const WEB42_IGNORE_CONTENT = [
|
|
39
|
-
"# .web42ignore — files excluded from web42 pack / push",
|
|
40
|
-
"# Syntax: glob patterns, one per line. Lines starting with # are comments.",
|
|
41
|
-
"# NOTE: .git, node_modules, .web42/, manifest.json, and other internals",
|
|
42
|
-
"# are always excluded automatically.",
|
|
43
|
-
"",
|
|
44
|
-
"# Working notes & drafts",
|
|
45
|
-
"TODO.md",
|
|
46
|
-
"NOTES.md",
|
|
47
|
-
"drafts/**",
|
|
48
|
-
"",
|
|
49
|
-
"# Environment & secrets",
|
|
50
|
-
".env",
|
|
51
|
-
".env.*",
|
|
52
|
-
"",
|
|
53
|
-
"# IDE / editor",
|
|
54
|
-
".vscode/**",
|
|
55
|
-
".idea/**",
|
|
56
|
-
".cursor/**",
|
|
57
|
-
"",
|
|
58
|
-
"# Test & CI",
|
|
59
|
-
"tests/**",
|
|
60
|
-
"__tests__/**",
|
|
61
|
-
".github/**",
|
|
62
|
-
"",
|
|
63
|
-
"# Build artifacts",
|
|
64
|
-
"dist/**",
|
|
65
|
-
"build/**",
|
|
66
|
-
"",
|
|
67
|
-
"# Large media not needed at runtime",
|
|
68
|
-
"# *.mp4",
|
|
69
|
-
"# *.mov",
|
|
70
|
-
"",
|
|
71
|
-
].join("\n");
|
|
72
|
-
// ---------------------------------------------------------------------------
|
|
73
|
-
// Claude-specific init flow
|
|
74
|
-
// ---------------------------------------------------------------------------
|
|
75
|
-
async function initClaude(cwd, config, adapter) {
|
|
76
|
-
// Discover agents
|
|
77
|
-
if (!adapter.discoverAgents) {
|
|
78
|
-
console.log(chalk.red("Claude adapter missing discoverAgents method."));
|
|
79
|
-
process.exit(1);
|
|
80
|
-
}
|
|
81
|
-
const agents = adapter.discoverAgents(cwd);
|
|
82
|
-
if (agents.length === 0) {
|
|
83
|
-
console.log(chalk.red("No agents found.\n" +
|
|
84
|
-
"Create an agent in ~/.claude/agents/ or ./agents/ first."));
|
|
85
|
-
process.exit(1);
|
|
86
|
-
}
|
|
87
|
-
// Agent picker (multi-select)
|
|
88
|
-
let selectedAgents = agents;
|
|
89
|
-
if (agents.length > 1) {
|
|
90
|
-
const { chosen } = await inquirer.prompt([
|
|
91
|
-
{
|
|
92
|
-
type: "checkbox",
|
|
93
|
-
name: "chosen",
|
|
94
|
-
message: "Which agents do you want to init for the marketplace?",
|
|
95
|
-
choices: agents.map((a) => ({
|
|
96
|
-
name: `${a.name}${a.description ? ` — ${a.description}` : ""}`,
|
|
97
|
-
value: a.name,
|
|
98
|
-
checked: true,
|
|
99
|
-
})),
|
|
100
|
-
validate: (val) => val.length > 0 || "Select at least one agent",
|
|
101
|
-
},
|
|
102
|
-
]);
|
|
103
|
-
selectedAgents = agents.filter((a) => chosen.includes(a.name));
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
console.log();
|
|
107
|
-
console.log(chalk.dim(` Found agent: ${chalk.bold(agents[0].name)}${agents[0].description ? ` — ${agents[0].description}` : ""}`));
|
|
108
|
-
}
|
|
109
|
-
// Check for existing .web42/ agents that are already init'd
|
|
110
|
-
const web42Dir = join(cwd, ".web42");
|
|
111
|
-
const existingInits = new Set();
|
|
112
|
-
if (existsSync(web42Dir)) {
|
|
113
|
-
try {
|
|
114
|
-
const entries = readdirSync(web42Dir, { withFileTypes: true });
|
|
115
|
-
for (const entry of entries) {
|
|
116
|
-
if (entry.isDirectory() && existsSync(join(web42Dir, entry.name, "manifest.json"))) {
|
|
117
|
-
existingInits.add(entry.name);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
// skip
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
const toInit = selectedAgents.filter((a) => !existingInits.has(a.name));
|
|
126
|
-
const alreadyInit = selectedAgents.filter((a) => existingInits.has(a.name));
|
|
127
|
-
if (alreadyInit.length > 0) {
|
|
128
|
-
console.log(chalk.dim(` Already initialized: ${alreadyInit.map((a) => a.name).join(", ")}`));
|
|
129
|
-
}
|
|
130
|
-
if (toInit.length === 0 && alreadyInit.length > 0) {
|
|
131
|
-
// Ask if they want to re-init
|
|
132
|
-
const { reinit } = await inquirer.prompt([
|
|
133
|
-
{
|
|
134
|
-
type: "confirm",
|
|
135
|
-
name: "reinit",
|
|
136
|
-
message: "All selected agents are already initialized. Re-initialize?",
|
|
137
|
-
default: false,
|
|
138
|
-
},
|
|
139
|
-
]);
|
|
140
|
-
if (!reinit) {
|
|
141
|
-
console.log(chalk.yellow("Aborted."));
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
toInit.push(...alreadyInit);
|
|
145
|
-
}
|
|
146
|
-
// For each agent: resolve skills, prompt, create .web42/{name}/ metadata
|
|
147
|
-
for (const agent of toInit.length > 0 ? toInit : selectedAgents) {
|
|
148
|
-
console.log();
|
|
149
|
-
console.log(chalk.bold(`Initializing ${agent.name}...`));
|
|
150
|
-
// Resolve skills
|
|
151
|
-
let resolvedSkills = [];
|
|
152
|
-
if (agent.skills.length > 0 && adapter.resolveSkills) {
|
|
153
|
-
const resolved = adapter.resolveSkills(agent.skills, cwd);
|
|
154
|
-
const found = resolved.filter((s) => s.found);
|
|
155
|
-
const missing = resolved.filter((s) => !s.found);
|
|
156
|
-
if (found.length > 0) {
|
|
157
|
-
// Read SKILL.md for descriptions
|
|
158
|
-
resolvedSkills = found.map((s) => {
|
|
159
|
-
const skillMd = join(s.sourcePath, "SKILL.md");
|
|
160
|
-
if (existsSync(skillMd)) {
|
|
161
|
-
const content = readFileSync(skillMd, "utf-8");
|
|
162
|
-
const parsed = parseSkillMd(content, s.name);
|
|
163
|
-
return { name: parsed.name, description: parsed.description };
|
|
164
|
-
}
|
|
165
|
-
return { name: s.name, description: `Skill: ${s.name}` };
|
|
166
|
-
});
|
|
167
|
-
console.log(chalk.dim(` Resolved ${found.length} skill(s): ${found.map((s) => s.name).join(", ")}`));
|
|
168
|
-
}
|
|
169
|
-
if (missing.length > 0) {
|
|
170
|
-
console.log(chalk.yellow(` Skills not found: ${missing.map((s) => s.name).join(", ")}`));
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
// Also detect workspace skills (in case agent references skills in cwd/skills/)
|
|
174
|
-
const workspaceSkills = detectWorkspaceSkills(cwd);
|
|
175
|
-
const existingNames = new Set(resolvedSkills.map((s) => s.name));
|
|
176
|
-
for (const ws of workspaceSkills) {
|
|
177
|
-
if (!existingNames.has(ws.name)) {
|
|
178
|
-
resolvedSkills.push(ws);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
// Prompt for description and version
|
|
182
|
-
const defaults = {
|
|
183
|
-
description: agent.description ?? "",
|
|
184
|
-
version: "1.0.0",
|
|
185
|
-
};
|
|
186
|
-
// Check if manifest already exists for this agent
|
|
187
|
-
const agentWeb42Dir = join(web42Dir, agent.name);
|
|
188
|
-
const existingManifestPath = join(agentWeb42Dir, "manifest.json");
|
|
189
|
-
let existingManifest = null;
|
|
190
|
-
if (existsSync(existingManifestPath)) {
|
|
191
|
-
try {
|
|
192
|
-
existingManifest = JSON.parse(readFileSync(existingManifestPath, "utf-8"));
|
|
193
|
-
}
|
|
194
|
-
catch {
|
|
195
|
-
// ignore
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
const answers = await inquirer.prompt([
|
|
199
|
-
{
|
|
200
|
-
type: "input",
|
|
201
|
-
name: "description",
|
|
202
|
-
message: ` Description for ${agent.name}:`,
|
|
203
|
-
default: existingManifest?.description ?? defaults.description,
|
|
204
|
-
validate: (val) => (val.length > 0 && val.length <= 500) || "1-500 characters",
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
type: "input",
|
|
208
|
-
name: "version",
|
|
209
|
-
message: " Version:",
|
|
210
|
-
default: existingManifest?.version ?? defaults.version,
|
|
211
|
-
validate: (val) => /^\d+\.\d+\.\d+$/.test(val) || "Must follow semver (e.g. 1.0.0)",
|
|
212
|
-
},
|
|
213
|
-
]);
|
|
214
|
-
// Create per-agent .web42/{name}/ directory
|
|
215
|
-
mkdirSync(agentWeb42Dir, { recursive: true });
|
|
216
|
-
// Write manifest
|
|
217
|
-
const manifest = {
|
|
218
|
-
format: "agentpkg/1",
|
|
219
|
-
platform: "claude",
|
|
220
|
-
name: agent.name,
|
|
221
|
-
description: answers.description,
|
|
222
|
-
version: answers.version,
|
|
223
|
-
author: config.username ?? "",
|
|
224
|
-
skills: resolvedSkills,
|
|
225
|
-
plugins: [],
|
|
226
|
-
modelPreferences: agent.model
|
|
227
|
-
? { primary: agent.model }
|
|
228
|
-
: undefined,
|
|
229
|
-
configVariables: [],
|
|
230
|
-
};
|
|
231
|
-
writeFileSync(join(agentWeb42Dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
232
|
-
console.log(chalk.green(` Created .web42/${agent.name}/manifest.json`));
|
|
233
|
-
// Write marketplace.json
|
|
234
|
-
const marketplacePath = join(agentWeb42Dir, "marketplace.json");
|
|
235
|
-
if (!existsSync(marketplacePath)) {
|
|
236
|
-
writeFileSync(marketplacePath, JSON.stringify(DEFAULT_MARKETPLACE, null, 2) + "\n");
|
|
237
|
-
console.log(chalk.green(` Created .web42/${agent.name}/marketplace.json`));
|
|
238
|
-
}
|
|
239
|
-
// Write .web42ignore
|
|
240
|
-
const ignorePath = join(agentWeb42Dir, ".web42ignore");
|
|
241
|
-
if (!existsSync(ignorePath)) {
|
|
242
|
-
writeFileSync(ignorePath, WEB42_IGNORE_CONTENT, "utf-8");
|
|
243
|
-
console.log(chalk.green(` Created .web42/${agent.name}/.web42ignore`));
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
console.log();
|
|
247
|
-
console.log(chalk.dim("Edit .web42/{agent}/marketplace.json to set price, tags, license, and visibility."));
|
|
248
|
-
console.log(chalk.dim("Run `web42 pack` to bundle your agents, or `web42 push` to pack and publish."));
|
|
249
|
-
}
|
|
250
|
-
// ---------------------------------------------------------------------------
|
|
251
|
-
// OpenClaw init flow (existing behavior)
|
|
252
|
-
// ---------------------------------------------------------------------------
|
|
253
|
-
async function initOpenclaw(cwd, config, adapter, platform, opts) {
|
|
254
|
-
const manifestPath = join(cwd, "manifest.json");
|
|
255
|
-
let existingManifest = null;
|
|
256
|
-
if (existsSync(manifestPath)) {
|
|
257
|
-
const { overwrite } = await inquirer.prompt([
|
|
258
|
-
{
|
|
259
|
-
type: "confirm",
|
|
260
|
-
name: "overwrite",
|
|
261
|
-
message: "manifest.json already exists. Overwrite?",
|
|
262
|
-
default: false,
|
|
263
|
-
},
|
|
264
|
-
]);
|
|
265
|
-
if (!overwrite) {
|
|
266
|
-
console.log(chalk.yellow("Aborted."));
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
existingManifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
271
|
-
}
|
|
272
|
-
catch {
|
|
273
|
-
// ignore
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
const initConfig = adapter.extractInitConfig(cwd);
|
|
277
|
-
if (!initConfig) {
|
|
278
|
-
console.log(chalk.red(`No agent entry found in ${adapter.name} config for this directory.\n` +
|
|
279
|
-
`Set up your agent in ${adapter.name} first.`));
|
|
280
|
-
process.exit(1);
|
|
281
|
-
}
|
|
282
|
-
console.log();
|
|
283
|
-
console.log(chalk.dim(` Agent: ${chalk.bold(initConfig.name)} (from ${adapter.name} config)`));
|
|
284
|
-
if (initConfig.model) {
|
|
285
|
-
console.log(chalk.dim(` Model: ${initConfig.model}`));
|
|
286
|
-
}
|
|
287
|
-
console.log();
|
|
288
|
-
const answers = await inquirer.prompt([
|
|
289
|
-
{
|
|
290
|
-
type: "input",
|
|
291
|
-
name: "description",
|
|
292
|
-
message: "Short description:",
|
|
293
|
-
default: existingManifest?.description ?? "",
|
|
294
|
-
validate: (val) => (val.length > 0 && val.length <= 500) || "1-500 characters",
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
type: "input",
|
|
298
|
-
name: "version",
|
|
299
|
-
message: "Version:",
|
|
300
|
-
default: existingManifest?.version ?? "1.0.0",
|
|
301
|
-
validate: (val) => /^\d+\.\d+\.\d+$/.test(val) || "Must follow semver (e.g. 1.0.0)",
|
|
302
|
-
},
|
|
303
|
-
]);
|
|
304
|
-
const detectedSkills = detectWorkspaceSkills(cwd);
|
|
305
|
-
if (detectedSkills.length > 0) {
|
|
306
|
-
console.log(chalk.dim(` Detected ${detectedSkills.length} skill(s): ${detectedSkills.map((s) => s.name).join(", ")}`));
|
|
307
|
-
}
|
|
308
|
-
const manifest = {
|
|
309
|
-
format: "agentpkg/1",
|
|
310
|
-
platform,
|
|
311
|
-
name: initConfig.name,
|
|
312
|
-
description: answers.description,
|
|
313
|
-
version: answers.version,
|
|
314
|
-
author: config.username ?? "",
|
|
315
|
-
skills: detectedSkills,
|
|
316
|
-
plugins: [],
|
|
317
|
-
modelPreferences: initConfig.model
|
|
318
|
-
? { primary: initConfig.model }
|
|
319
|
-
: undefined,
|
|
320
|
-
configVariables: [],
|
|
321
|
-
};
|
|
322
|
-
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
323
|
-
console.log();
|
|
324
|
-
console.log(chalk.green(`Created ${chalk.bold("manifest.json")}`));
|
|
325
|
-
const scaffoldFiles = [
|
|
326
|
-
{ name: "AGENTS.md", content: AGENTS_MD, alwaysWrite: false },
|
|
327
|
-
{ name: "IDENTITY.md", content: IDENTITY_MD, alwaysWrite: false },
|
|
328
|
-
{ name: "SOUL.md", content: SOUL_MD, alwaysWrite: false },
|
|
329
|
-
{ name: "TOOLS.md", content: TOOLS_MD, alwaysWrite: false },
|
|
330
|
-
{ name: "HEARTBEAT.md", content: HEARTBEAT_MD, alwaysWrite: false },
|
|
331
|
-
{ name: "BOOTSTRAP.md", content: INIT_BOOTSTRAP_MD, alwaysWrite: false },
|
|
332
|
-
{ name: "USER.md", content: USER_MD, alwaysWrite: true },
|
|
333
|
-
];
|
|
334
|
-
const created = [];
|
|
335
|
-
const skipped = [];
|
|
336
|
-
for (const file of scaffoldFiles) {
|
|
337
|
-
const filePath = join(cwd, file.name);
|
|
338
|
-
if (!file.alwaysWrite && existsSync(filePath)) {
|
|
339
|
-
skipped.push(file.name);
|
|
340
|
-
continue;
|
|
341
|
-
}
|
|
342
|
-
writeFileSync(filePath, file.content, "utf-8");
|
|
343
|
-
created.push(file.name);
|
|
344
|
-
}
|
|
345
|
-
if (created.length > 0) {
|
|
346
|
-
console.log(chalk.green(` Scaffolded: ${created.join(", ")}`));
|
|
347
|
-
}
|
|
348
|
-
if (skipped.length > 0) {
|
|
349
|
-
console.log(chalk.dim(` Skipped (already exist): ${skipped.join(", ")}`));
|
|
350
|
-
}
|
|
351
|
-
// Scaffold .web42/ metadata folder
|
|
352
|
-
const web42Dir = join(cwd, ".web42");
|
|
353
|
-
mkdirSync(web42Dir, { recursive: true });
|
|
354
|
-
const marketplacePath = join(web42Dir, "marketplace.json");
|
|
355
|
-
if (!existsSync(marketplacePath)) {
|
|
356
|
-
writeMarketplace(cwd, { ...DEFAULT_MARKETPLACE });
|
|
357
|
-
console.log(chalk.green(` Created ${chalk.bold(".web42/marketplace.json")}`));
|
|
358
|
-
}
|
|
359
|
-
else {
|
|
360
|
-
console.log(chalk.dim(" Skipped .web42/marketplace.json (already exists)"));
|
|
361
|
-
}
|
|
362
|
-
const resourcesJsonPath = join(web42Dir, "resources.json");
|
|
363
|
-
if (!existsSync(resourcesJsonPath)) {
|
|
364
|
-
writeResourcesMeta(cwd, []);
|
|
365
|
-
console.log(chalk.green(` Created ${chalk.bold(".web42/resources.json")}`));
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
console.log(chalk.dim(" Skipped .web42/resources.json (already exists)"));
|
|
369
|
-
}
|
|
370
|
-
mkdirSync(join(web42Dir, "resources"), { recursive: true });
|
|
371
|
-
const ignorePath = join(cwd, ".web42ignore");
|
|
372
|
-
if (!existsSync(ignorePath)) {
|
|
373
|
-
writeFileSync(ignorePath, WEB42_IGNORE_CONTENT, "utf-8");
|
|
374
|
-
console.log(chalk.green(` Created ${chalk.bold(".web42ignore")}`));
|
|
375
|
-
}
|
|
376
|
-
else {
|
|
377
|
-
console.log(chalk.dim(" Skipped .web42ignore (already exists)"));
|
|
378
|
-
}
|
|
379
|
-
// Offer bundled starter skills
|
|
380
|
-
const bundled = listBundledSkills();
|
|
381
|
-
if (bundled.length > 0) {
|
|
382
|
-
let skillsToInstall = [];
|
|
383
|
-
if (opts.withSkills === true) {
|
|
384
|
-
skillsToInstall = bundled.map((s) => s.name);
|
|
385
|
-
}
|
|
386
|
-
else if (Array.isArray(opts.withSkills) && opts.withSkills.length > 0) {
|
|
387
|
-
skillsToInstall = opts.withSkills.filter((name) => bundled.some((s) => s.name === name));
|
|
388
|
-
const unknown = opts.withSkills.filter((name) => !bundled.some((s) => s.name === name));
|
|
389
|
-
if (unknown.length > 0) {
|
|
390
|
-
console.log(chalk.yellow(` Unknown skill(s): ${unknown.join(", ")}`));
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
else if (!opts.withSkills) {
|
|
394
|
-
console.log();
|
|
395
|
-
const { selectedSkills } = await inquirer.prompt([
|
|
396
|
-
{
|
|
397
|
-
type: "checkbox",
|
|
398
|
-
name: "selectedSkills",
|
|
399
|
-
message: "Add starter skills to your workspace?",
|
|
400
|
-
choices: bundled.map((s) => ({
|
|
401
|
-
name: `${s.name} — ${s.description}`,
|
|
402
|
-
value: s.name,
|
|
403
|
-
checked: false,
|
|
404
|
-
})),
|
|
405
|
-
},
|
|
406
|
-
]);
|
|
407
|
-
skillsToInstall = selectedSkills;
|
|
408
|
-
}
|
|
409
|
-
if (skillsToInstall.length > 0) {
|
|
410
|
-
const installed = [];
|
|
411
|
-
for (const name of skillsToInstall) {
|
|
412
|
-
if (copySkillToWorkspace(name, cwd)) {
|
|
413
|
-
installed.push(name);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
if (installed.length > 0) {
|
|
417
|
-
console.log(chalk.green(` Added starter skill(s): ${installed.join(", ")}`));
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
console.log();
|
|
422
|
-
console.log(chalk.dim("Edit .web42/marketplace.json to set price, tags, license, and visibility."));
|
|
423
|
-
console.log(chalk.dim("Run `web42 pack` to bundle your agent, or `web42 push` to pack and publish."));
|
|
424
|
-
}
|
|
425
|
-
// ---------------------------------------------------------------------------
|
|
426
|
-
// Command
|
|
427
|
-
// ---------------------------------------------------------------------------
|
|
428
|
-
export const initCommand = new Command("init")
|
|
429
|
-
.description("Create a manifest.json for your agent package")
|
|
430
|
-
.option("--with-skills [names...]", "Add bundled starter skills (omit names to install all)")
|
|
431
|
-
.action(async (opts) => {
|
|
432
|
-
const config = requireAuth();
|
|
433
|
-
const cwd = process.cwd();
|
|
434
|
-
const platforms = listPlatforms();
|
|
435
|
-
const { platform } = await inquirer.prompt([
|
|
436
|
-
{
|
|
437
|
-
type: "list",
|
|
438
|
-
name: "platform",
|
|
439
|
-
message: "Platform:",
|
|
440
|
-
choices: platforms,
|
|
441
|
-
default: platforms[0],
|
|
442
|
-
},
|
|
443
|
-
]);
|
|
444
|
-
const adapter = resolvePlatform(platform);
|
|
445
|
-
if (platform === "claude") {
|
|
446
|
-
await initClaude(cwd, config, adapter);
|
|
447
|
-
}
|
|
448
|
-
else {
|
|
449
|
-
await initOpenclaw(cwd, config, adapter, platform, opts);
|
|
450
|
-
}
|
|
451
|
-
});
|
package/dist/commands/install.js
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
3
|
-
import { Command } from "commander";
|
|
4
|
-
import chalk from "chalk";
|
|
5
|
-
import inquirer from "inquirer";
|
|
6
|
-
import ora from "ora";
|
|
7
|
-
import { apiGet, apiPost } from "../utils/api.js";
|
|
8
|
-
function deriveProviderEnvKey(model) {
|
|
9
|
-
const slash = model.indexOf("/");
|
|
10
|
-
if (slash < 1)
|
|
11
|
-
return null;
|
|
12
|
-
const provider = model.slice(0, slash);
|
|
13
|
-
const envKey = `${provider.toUpperCase().replace(/-/g, "_")}_API_KEY`;
|
|
14
|
-
return { provider, envKey };
|
|
15
|
-
}
|
|
16
|
-
function isKeyConfigured(envKey, platformHome) {
|
|
17
|
-
if (process.env[envKey])
|
|
18
|
-
return true;
|
|
19
|
-
const dotenvPath = join(platformHome, ".env");
|
|
20
|
-
if (!existsSync(dotenvPath))
|
|
21
|
-
return false;
|
|
22
|
-
try {
|
|
23
|
-
const content = readFileSync(dotenvPath, "utf-8");
|
|
24
|
-
return content.split("\n").some((line) => {
|
|
25
|
-
const trimmed = line.trim();
|
|
26
|
-
if (trimmed.startsWith("#"))
|
|
27
|
-
return false;
|
|
28
|
-
const eqIdx = trimmed.indexOf("=");
|
|
29
|
-
return eqIdx > 0 && trimmed.slice(0, eqIdx).trim() === envKey;
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function appendToEnv(envKey, value, platformHome) {
|
|
37
|
-
const dotenvPath = join(platformHome, ".env");
|
|
38
|
-
const line = `${envKey}=${value}\n`;
|
|
39
|
-
appendFileSync(dotenvPath, line, "utf-8");
|
|
40
|
-
}
|
|
41
|
-
export function makeInstallCommand(adapter) {
|
|
42
|
-
return new Command("install")
|
|
43
|
-
.description("Install an agent package from the marketplace")
|
|
44
|
-
.argument("<agent>", "Agent to install (e.g. @user/agent-name)")
|
|
45
|
-
.option("--as <name>", "Install under a different local agent name")
|
|
46
|
-
.option("--no-prompt", "Skip config variable prompts, use defaults")
|
|
47
|
-
.option("-g, --global", "Install globally to ~/.claude/ instead of project-local .claude/")
|
|
48
|
-
.action(async (agentRef, opts) => {
|
|
49
|
-
const match = agentRef.match(/^@?([^/]+)\/(.+)$/);
|
|
50
|
-
if (!match) {
|
|
51
|
-
console.log(chalk.red("Invalid agent reference. Use @user/agent-name format."));
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
const [, username, agentSlug] = match;
|
|
55
|
-
const spinner = ora(`Fetching @${username}/${agentSlug}...`).start();
|
|
56
|
-
try {
|
|
57
|
-
const agents = await apiGet(`/api/agents?username=${username}`);
|
|
58
|
-
const agent = agents.find((a) => a.slug === agentSlug);
|
|
59
|
-
if (!agent) {
|
|
60
|
-
spinner.fail(`Agent @${username}/${agentSlug} not found`);
|
|
61
|
-
process.exit(1);
|
|
62
|
-
}
|
|
63
|
-
let result;
|
|
64
|
-
try {
|
|
65
|
-
result = await apiPost(`/api/agents/${agent.id}/install`, {});
|
|
66
|
-
}
|
|
67
|
-
catch (err) {
|
|
68
|
-
if (err.message?.includes("Access required") &&
|
|
69
|
-
agent.price_cents > 0) {
|
|
70
|
-
const siteUrl = process.env.WEB42_API_URL ?? "https://web42.ai";
|
|
71
|
-
spinner.fail(`This is a paid agent ($${(agent.price_cents / 100).toFixed(2)}). Purchase it on the web first:`);
|
|
72
|
-
console.log(chalk.cyan(` ${siteUrl}/${username}/${agentSlug}`));
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
throw err;
|
|
76
|
-
}
|
|
77
|
-
const manifest = result.agent.manifest;
|
|
78
|
-
let configAnswers = {};
|
|
79
|
-
if (manifest.configVariables && manifest.configVariables.length > 0) {
|
|
80
|
-
if (opts.prompt === false) {
|
|
81
|
-
for (const v of manifest.configVariables) {
|
|
82
|
-
configAnswers[v.key] = v.default ?? "";
|
|
83
|
-
}
|
|
84
|
-
spinner.text = "Installing agent (skipping prompts)...";
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
spinner.stop();
|
|
88
|
-
console.log();
|
|
89
|
-
console.log(chalk.bold("Configure your agent:"));
|
|
90
|
-
console.log();
|
|
91
|
-
configAnswers = await inquirer.prompt(manifest.configVariables.map((v) => ({
|
|
92
|
-
type: "input",
|
|
93
|
-
name: v.key,
|
|
94
|
-
message: `${v.label}${v.description ? ` (${v.description})` : ""}:`,
|
|
95
|
-
default: v.default,
|
|
96
|
-
validate: (val) => !v.required || val.length > 0 || `${v.label} is required`,
|
|
97
|
-
})));
|
|
98
|
-
spinner.start("Installing agent...");
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
spinner.text = "Installing agent...";
|
|
103
|
-
}
|
|
104
|
-
const primaryModel = manifest.modelPreferences?.primary;
|
|
105
|
-
if (primaryModel) {
|
|
106
|
-
const providerInfo = deriveProviderEnvKey(primaryModel);
|
|
107
|
-
if (providerInfo) {
|
|
108
|
-
if (isKeyConfigured(providerInfo.envKey, adapter.home)) {
|
|
109
|
-
if (spinner.isSpinning)
|
|
110
|
-
spinner.stop();
|
|
111
|
-
console.log(chalk.dim(` ${providerInfo.envKey} already configured for ${primaryModel}`));
|
|
112
|
-
if (!spinner.isSpinning)
|
|
113
|
-
spinner.start("Installing agent...");
|
|
114
|
-
}
|
|
115
|
-
else if (opts.prompt === false) {
|
|
116
|
-
if (spinner.isSpinning)
|
|
117
|
-
spinner.stop();
|
|
118
|
-
console.log();
|
|
119
|
-
console.log(chalk.yellow(` This agent uses ${chalk.bold(primaryModel)}. You'll need to set ${chalk.bold(providerInfo.envKey)} in ${adapter.home}/.env or as an environment variable.`));
|
|
120
|
-
spinner.start("Installing agent...");
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
if (spinner.isSpinning)
|
|
124
|
-
spinner.stop();
|
|
125
|
-
console.log();
|
|
126
|
-
console.log(chalk.bold(`This agent uses ${chalk.cyan(primaryModel)}.`));
|
|
127
|
-
const { apiKey } = await inquirer.prompt([
|
|
128
|
-
{
|
|
129
|
-
type: "password",
|
|
130
|
-
name: "apiKey",
|
|
131
|
-
message: `Enter your ${providerInfo.envKey} (leave empty to skip):`,
|
|
132
|
-
mask: "*",
|
|
133
|
-
},
|
|
134
|
-
]);
|
|
135
|
-
if (apiKey) {
|
|
136
|
-
appendToEnv(providerInfo.envKey, apiKey, adapter.home);
|
|
137
|
-
console.log(chalk.green(` Saved ${providerInfo.envKey} to ${adapter.home}/.env`));
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
console.log(chalk.yellow(` Skipped. Set ${chalk.bold(providerInfo.envKey)} in ${adapter.home}/.env later.`));
|
|
141
|
-
}
|
|
142
|
-
spinner.start("Installing agent...");
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
let configTemplate = null;
|
|
147
|
-
const configFile = result.files.find((f) => f.path === ".openclaw/config.json" && f.content);
|
|
148
|
-
if (configFile?.content) {
|
|
149
|
-
try {
|
|
150
|
-
configTemplate = JSON.parse(configFile.content);
|
|
151
|
-
}
|
|
152
|
-
catch {
|
|
153
|
-
// No config template available
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
const localName = opts.as ?? agentSlug;
|
|
157
|
-
const workspacePath = adapter.resolveInstallPath
|
|
158
|
-
? adapter.resolveInstallPath(localName, opts.global)
|
|
159
|
-
: opts.global
|
|
160
|
-
? join(adapter.home, `workspace-${localName}`)
|
|
161
|
-
: join(process.cwd(), ".claude");
|
|
162
|
-
const installResult = await adapter.install({
|
|
163
|
-
agentSlug: localName,
|
|
164
|
-
username,
|
|
165
|
-
workspacePath,
|
|
166
|
-
files: result.files,
|
|
167
|
-
configTemplate,
|
|
168
|
-
configAnswers,
|
|
169
|
-
version: result.agent.manifest.version,
|
|
170
|
-
});
|
|
171
|
-
const web42Config = {
|
|
172
|
-
source: `@${username}/${agentSlug}`,
|
|
173
|
-
...configAnswers,
|
|
174
|
-
};
|
|
175
|
-
const configPath = join(workspacePath, ".web42.config.json");
|
|
176
|
-
writeFileSync(configPath, JSON.stringify(web42Config, null, 2) + "\n");
|
|
177
|
-
spinner.stop();
|
|
178
|
-
const profileImageUrl = result.agent.profile_image_url;
|
|
179
|
-
if (profileImageUrl) {
|
|
180
|
-
try {
|
|
181
|
-
const avatarsDir = join(workspacePath, "avatars");
|
|
182
|
-
mkdirSync(avatarsDir, { recursive: true });
|
|
183
|
-
const avatarPath = join(avatarsDir, "avatar.png");
|
|
184
|
-
const avatarResponse = await fetch(profileImageUrl);
|
|
185
|
-
if (avatarResponse.ok) {
|
|
186
|
-
const buffer = Buffer.from(await avatarResponse.arrayBuffer());
|
|
187
|
-
writeFileSync(avatarPath, buffer);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
catch {
|
|
191
|
-
// Non-fatal — avatar download failure shouldn't block install
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
console.log();
|
|
195
|
-
console.log(chalk.green(`Installed ${chalk.bold(`@${username}/${agentSlug}`)} as agent "${localName}"`));
|
|
196
|
-
console.log(chalk.dim(` Workspace: ${workspacePath}`));
|
|
197
|
-
if (manifest.skills && manifest.skills.length > 0) {
|
|
198
|
-
const skillNames = manifest.skills.map((s) => typeof s === "string" ? s : s.name);
|
|
199
|
-
console.log(chalk.dim(` Skills: ${skillNames.join(", ")}`));
|
|
200
|
-
}
|
|
201
|
-
console.log(chalk.dim(` ${installResult.filesWritten} files written`));
|
|
202
|
-
const pendingVars = (manifest.configVariables ?? []).filter((v) => v.required && !configAnswers[v.key]);
|
|
203
|
-
if (pendingVars.length > 0) {
|
|
204
|
-
console.log();
|
|
205
|
-
console.log(chalk.yellow(` ${pendingVars.length} config variable(s) still need setup:`));
|
|
206
|
-
for (const v of pendingVars) {
|
|
207
|
-
console.log(chalk.yellow(` - ${v.label} (${v.key})`));
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
console.log();
|
|
211
|
-
if (adapter.name === "claude") {
|
|
212
|
-
if (opts.global) {
|
|
213
|
-
console.log(chalk.dim(" Next: Open Claude Code — the agent is available globally."));
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
console.log(chalk.dim(" Next: Open Claude Code in this project — the agent is available locally."));
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
else {
|
|
220
|
-
console.log(chalk.dim(" Next steps:"));
|
|
221
|
-
console.log(chalk.dim(` 1. Set up channel bindings: ${adapter.name} config`));
|
|
222
|
-
console.log(chalk.dim(` 2. Restart the gateway: ${adapter.name} gateway restart`));
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
catch (error) {
|
|
226
|
-
spinner.fail("Install failed");
|
|
227
|
-
console.error(chalk.red(error.message));
|
|
228
|
-
process.exit(1);
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
}
|
package/dist/commands/list.d.ts
DELETED