@web42/cli 0.1.6 → 0.1.8
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/init.js +65 -1
- package/dist/commands/pack.js +11 -2
- package/dist/commands/pull.js +88 -17
- package/dist/commands/push.js +130 -66
- package/dist/commands/sync.d.ts +2 -0
- package/dist/commands/sync.js +98 -0
- package/dist/generated/embedded-skills.js +17 -5
- package/dist/index.js +2 -0
- package/dist/platforms/base.d.ts +1 -0
- package/dist/platforms/openclaw/adapter.d.ts +1 -0
- package/dist/platforms/openclaw/adapter.js +2 -2
- package/dist/types/sync.d.ts +74 -0
- package/dist/types/sync.js +7 -0
- package/dist/utils/api.d.ts +2 -0
- package/dist/utils/api.js +26 -0
- package/dist/utils/sync.d.ts +12 -0
- package/dist/utils/sync.js +197 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/web42-publish-prep/SKILL.md +84 -23
- package/skills/web42-publish-prep/_meta.json +3 -3
- package/skills/web42-publish-prep/assets/readme-template.md +9 -5
- package/skills/web42-publish-prep/references/file-hygiene.md +30 -9
- package/skills/web42-publish-prep/references/manifest-fields.md +4 -1
- package/skills/web42-publish-prep/references/marketplace-config.md +99 -0
- package/skills/web42-publish-prep/references/resources-guide.md +136 -0
- package/skills/web42-publish-prep/references/web42-folder.md +120 -0
|
@@ -5,23 +5,35 @@ export const EMBEDDED_SKILLS = [
|
|
|
5
5
|
files: [
|
|
6
6
|
{
|
|
7
7
|
path: "_meta.json",
|
|
8
|
-
content: "{\n \"name\": \"web42-publish-prep\",\n \"tagline\": \"Prepare your agent for the Web42 marketplace\",\n \"description\": \"Guides agents through the full publish lifecycle: init, manifest enrichment, README writing, file auditing, and
|
|
8
|
+
content: "{\n \"name\": \"web42-publish-prep\",\n \"tagline\": \"Prepare your agent for the Web42 marketplace\",\n \"description\": \"Guides agents through the full publish lifecycle: init, manifest enrichment, marketplace configuration (pricing, license, tags), visual assets (avatar, screenshots, demo media), README writing, file auditing, and two-way sync with the Web42 marketplace.\",\n \"category\": \"development\",\n \"tags\": [\"web42\", \"marketplace\", \"publishing\", \"cli\", \"agent-packaging\", \"sync\"],\n \"version\": \"2.0.0\",\n \"license\": \"MIT\",\n \"pricing\": \"free\",\n \"support_url\": \"https://github.com/web42-ai/web42-marketplace/issues\",\n \"homepage\": \"https://web42.ai/docs/publishing\",\n \"requiredConfigPaths\": [],\n \"primaryCredential\": null,\n \"requires\": {\n \"anyBins\": [\"web42\"]\n }\n}\n",
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
path: "assets/readme-template.md",
|
|
12
|
-
content: "# {Agent Name}\n\n<!-- \n This is a starting point, not a form. Rewrite it, restructure it, make it yours.\n The marketplace renders full Markdown — use it. GIFs, videos, screenshots, emoji, whatever tells your story.\n-->\n\n{A bold opening line. What changes for the user when they have you? Don't describe yourself — describe the outcome.}\n\n
|
|
12
|
+
content: "# {Agent Name}\n\n<!-- \n This is a starting point, not a form. Rewrite it, restructure it, make it yours.\n The marketplace renders full Markdown — use it. GIFs, videos, screenshots, emoji, whatever tells your story.\n \n Screenshots and demo media are managed in .web42/resources/ and appear automatically on the listing.\n The README is for the narrative — let the resources handle the visuals.\n-->\n\n{A bold opening line. What changes for the user when they have you? Don't describe yourself — describe the outcome.}\n\n---\n\n## What I Do\n\n{2–3 sentences, max. What's your superpower? Write this like you're explaining to a friend, not a spec sheet.}\n\n## Try Me\n\n{3–5 concrete scenarios. Not features — experiences. Make the reader feel what it's like to work with you.}\n\n- **\"Draft my weekly standup notes from yesterday's git commits and Slack threads.\"**\n- **\"Summarize this 40-page PDF into a one-page brief I can send to my team.\"**\n- **\"Monitor my inbox and ping me only when something actually matters.\"**\n\n<!-- Replace these with real scenarios that match what you actually do. -->\n\n## Install\n\n```bash\nweb42 openclaw install @{author}/{name}\n```\n\n{One sentence on what happens after install. Does the agent need a restart? A quick config? A first conversation?}\n\n## Configuration\n\n{List any API keys, tokens, or setup the user needs to provide. Be specific about where to find each one.}\n\n| Variable | What It Is | Where to Get It |\n|----------|-----------|-----------------|\n| `EXAMPLE_API_KEY` | Access token for Example API | [Example Dashboard > Settings > API](https://example.com/settings) |\n\n<!-- Remove this section entirely if the agent needs no configuration. -->\n\n---\n\n<!-- \n Optional sections you might add:\n - \"How I Work\" (high-level, no secrets — just enough to build trust)\n - \"Limitations\" (honesty builds credibility)\n - \"Changelog\" (what's new in this version)\n - \"Credits\" (shoutouts, inspirations)\n \n Or make up your own sections. There are no rules here.\n \n Tip: Your screenshots and demo video in .web42/resources/ will appear \n on the marketplace listing alongside this README. Focus the README on \n the story and let the media speak for the visual side.\n-->\n",
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
path: "references/file-hygiene.md",
|
|
16
|
-
content: "# File Hygiene Checklist\n\nBefore packing, audit the workspace for files that should not ship to buyers. The CLI's pack command automatically excludes some patterns, but manual review catches everything else.\n\n## Automatically Excluded by the CLI\n\nThese patterns are hardcoded in the pack command and will never appear in the `.web42/` artifact:\n\n| Pattern | Reason |\n|---------|--------|\n| `auth-profiles.json` | Platform authentication credentials |\n| `MEMORY.md` | Creator's long-term memory — personal context |\n| `memory/**` | Daily memory logs — personal context |\n| `sessions/**` | Session history — personal context |\n| `.git/**` | Version control internals |\n| `node_modules/**` | Dependencies (not portable) |\n| `.DS_Store` | macOS filesystem metadata |\n| `*.log` | Log files |\n| `openclaw.json` | Platform config (contains agent bindings, channel secrets) |\n| `.openclaw/credentials/**` | Platform credentials |\n| `.web42/**` |
|
|
16
|
+
content: "# File Hygiene Checklist\n\nBefore packing, audit the workspace for files that should not ship to buyers. The CLI's pack command automatically excludes some patterns, but manual review catches everything else.\n\n## Automatically Excluded by the CLI\n\nThese patterns are hardcoded in the pack command and will never appear in the `.web42/dist/` artifact:\n\n| Pattern | Reason |\n|---------|--------|\n| `auth-profiles.json` | Platform authentication credentials |\n| `MEMORY.md` | Creator's long-term memory — personal context |\n| `memory/**` | Daily memory logs — personal context |\n| `sessions/**` | Session history — personal context |\n| `.git/**` | Version control internals |\n| `node_modules/**` | Dependencies (not portable) |\n| `.DS_Store` | macOS filesystem metadata |\n| `*.log` | Log files |\n| `openclaw.json` | Platform config (contains agent bindings, channel secrets) |\n| `.openclaw/credentials/**` | Platform credentials |\n| `.web42/**` | Metadata folder (marketplace config, sync state, pack output) |\n| `.web42ignore` | Pack ignore config (meta, not content) |\n| `manifest.json` | Shipped separately as structured data |\n| `USER.md` | Always rewritten with a blank template on install |\n\n## `.web42/` Metadata Files (Not Packed)\n\nThe `.web42/` folder contains metadata and assets that are synced separately — they are NOT included in the packed agent files:\n\n| File | Purpose | Editable? |\n|------|---------|-----------|\n| `marketplace.json` | Pricing, license, tags | Yes |\n| `resources.json` | Resource file metadata | Yes |\n| `avatar.*` | Agent profile image | Yes |\n| `resources/` | Screenshots, videos, documents | Yes |\n| `sync.json` | Sync state tracking | No — auto-managed |\n| `dist/` | Pack output | No — auto-generated |\n\n**`sync.json`** should never be edited manually. Doing so will break change detection between local and remote. It is safe to delete if you want to force a full re-sync.\n\n## Files to Flag for Manual Review\n\nThese are NOT auto-excluded but often contain content that should not ship:\n\n### Personal Data\n\n- **`HEARTBEAT.md`** — If it contains creator-specific tasks, reminders, or routines. Reset to the scaffold default (empty with comments) unless the tasks are part of the agent's intended behavior.\n- **`SOUL.md`** — If it references the creator by name, contains personal preferences, or has inside jokes. Generalize to describe the agent's intended persona, not the creator's personality.\n- **`IDENTITY.md`** — If it contains the creator's chosen name/emoji/avatar. The buyer's agent should form its own identity. Reset to the scaffold template or write a persona description that fits the agent's purpose.\n- **`TOOLS.md`** — If it contains the creator's SSH hosts, camera names, device nicknames, etc. Reset to the scaffold template with example placeholders.\n\n### Secrets and Credentials\n\n- **`.env` / `.env.local`** — Should never be in the workspace root. If present, flag immediately.\n- **`.web42.config.json`** — Contains config variable values from the creator's install. Must not ship.\n- **Hardcoded API keys in skill files** — The CLI strips known patterns (`sk-...`, `ghp_...`, bearer tokens), but custom keys may slip through. Grep for suspicious patterns: long hex/base64 strings, `token`, `secret`, `password`, `apikey`.\n\n### Development Artifacts\n\n- **`.vscode/` / `.cursor/` / `.idea/`** — IDE configuration. Not relevant to buyers.\n- **`__pycache__/` / `*.pyc`** — Python bytecode.\n- **`Thumbs.db`** — Windows thumbnail cache.\n- **`*.bak` / `*.swp` / `*.tmp`** — Editor backup/swap files.\n- **`test/` / `tests/` / `__tests__/`** — Test files, unless they are part of the agent's functionality.\n- **Build outputs** — `dist/`, `build/`, `out/` directories.\n\n### Large or Binary Files\n\n- The pack command skips files larger than 1 MB.\n- Binary files (images, compiled executables) are skipped automatically (UTF-8 decode failure).\n- If the agent needs images (e.g., for the README cover), host them externally or manage them as resources in `.web42/resources/`.\n\n## Using `.web42ignore`\n\n`web42 init` scaffolds a default `.web42ignore` with sensible patterns (IDE folders, env files, test dirs, drafts). Edit it to match your workspace. Syntax: glob patterns, one per line — lines starting with `#` are comments.\n\n```\n# Exclude test fixtures\ntests/**\nfixtures/**\n\n# Exclude draft documents\ndrafts/**\n\n# Exclude local scripts not part of the agent\nscripts/local-*.sh\n```\n\nThe `.web42ignore` file itself is automatically excluded from the packed artifact.\n\n## Verification\n\nAfter auditing, always run:\n\n```\nweb42 pack --dry-run\n```\n\nThis prints:\n\n1. **User ignore patterns** loaded from `.web42ignore` (shown with ✕ prefix)\n2. **Every file** that would be included, with sizes\n3. **File and config variable counts**\n\nReview the output for:\n\n- **Unexpected files** — anything you don't recognize or didn't intend to ship\n- **File count** — a typical agent has 5–30 files. Hundreds of files suggests missing ignore patterns.\n- **Sensitive content** — spot-check a few files for leaked secrets or personal data\n",
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
path: "references/manifest-fields.md",
|
|
20
|
-
content: "# manifest.json Field Reference\n\nThe manifest describes your agent package. Format version is always `\"agentpkg/1\"`.\n\n## Required Fields\n\n### `name` (string)\n\nThe package identifier. Appears in install commands and URLs.\n\n- **Constraints:** 1–100 characters. Lowercase alphanumeric with hyphens only. Must start with a letter or number. Regex: `^[a-z0-9][a-z0-9-]*$`\n- **Good:** `support-bot`, `code-reviewer`, `daily-digest`\n- **Bad:** `My_Agent`, `Support Bot`, `-agent`\n- **Guidance:** Pick something short, memorable, and descriptive of what the agent does. This becomes the slug in `@author/name`.\n\n### `description` (string)\n\nA short pitch for the agent. Shown in search results and the marketplace listing.\n\n- **Constraints:** 1–500 characters.\n- **Good:** \"Drafts weekly team reports from your CRM data and posts them to Slack every Monday.\"\n- **Bad:** \"An AI agent.\" / \"This agent uses GPT-4 to process natural language queries against a database.\"\n- **Guidance:** Lead with the benefit to the user. What problem disappears? Avoid technical jargon about how it works internally.\n\n### `version` (string)\n\nSemantic version of the package.\n\n- **Constraints:** Must match `MAJOR.MINOR.PATCH` (e.g., `1.0.0`).\n- **Guidance:** Start at `1.0.0` for first publish. Bump `PATCH` for fixes, `MINOR` for new capabilities, `MAJOR` for breaking changes to config or behavior.\n\n### `author` (string)\n\nYour Web42 username. Set automatically by `web42 init` from your auth credentials.\n\n- **Constraints:** Non-empty string.\n- **Guidance:** Don't edit manually — it's populated from `web42 auth whoami`.\n\n## Optional Fields\n\n### `platform` (string)\n\nTarget agent platform.\n\n- **Values:** Currently only `\"openclaw\"`.\n- **Guidance:** Set during `web42 init` based on the platform prompt.\n\n### `skills` (array)\n\nList of skills the agent provides. Each entry has `name` (string) and `description` (string).\n\n- **Auto-detected** from `skills/*/SKILL.md` during init and pack.\n- **Guidance:** Don't edit manually. Add skills by creating `skills/<name>/SKILL.md` in your workspace. Internal skills (with `internal: true` in frontmatter) are automatically excluded.\n\n### `plugins` (string array)\n\nReserved for future use.\n\n- **Default:** `[]`\n- **Guidance:** Leave empty for now.\n\n### `modelPreferences` (object)\n\nPreferred LLM models for this agent.\n\n- **Fields:** `primary` (string, optional), `fallback` (string, optional)\n- **Example:** `{ \"primary\": \"claude-sonnet-4-20250514\" }`\n- **Guidance:** Set `primary` to the model the agent is designed and tested for. The `fallback` is used if the primary is unavailable. During install, the CLI will prompt buyers for the corresponding provider API key.\n\n### `tags` (string array)\n\nSearchable labels for marketplace discoverability.\n\n- **Default:** `[]`\n- **Good:** `[\"support\", \"crm\", \"slack\", \"weekly-reports\"]`\n- **Bad:** `[\"ai\", \"agent\", \"good\"]` (too generic)\n- **Guidance:** 3–6 tags. Think about what a buyer would search for. Mix category terms (\"support\", \"finance\") with capability terms (\"slack-integration\", \"pdf-generation\").\n\n### `coverImage` (string)\n\nPath to a cover image file, relative to workspace root.\n\n- **Guidance:** Optional
|
|
20
|
+
content: "# manifest.json Field Reference\n\nThe manifest describes your agent package. Format version is always `\"agentpkg/1\"`.\n\n## Required Fields\n\n### `name` (string)\n\nThe package identifier. Appears in install commands and URLs.\n\n- **Constraints:** 1–100 characters. Lowercase alphanumeric with hyphens only. Must start with a letter or number. Regex: `^[a-z0-9][a-z0-9-]*$`\n- **Good:** `support-bot`, `code-reviewer`, `daily-digest`\n- **Bad:** `My_Agent`, `Support Bot`, `-agent`\n- **Guidance:** Pick something short, memorable, and descriptive of what the agent does. This becomes the slug in `@author/name`.\n\n### `description` (string)\n\nA short pitch for the agent. Shown in search results and the marketplace listing.\n\n- **Constraints:** 1–500 characters.\n- **Good:** \"Drafts weekly team reports from your CRM data and posts them to Slack every Monday.\"\n- **Bad:** \"An AI agent.\" / \"This agent uses GPT-4 to process natural language queries against a database.\"\n- **Guidance:** Lead with the benefit to the user. What problem disappears? Avoid technical jargon about how it works internally.\n\n### `version` (string)\n\nSemantic version of the package.\n\n- **Constraints:** Must match `MAJOR.MINOR.PATCH` (e.g., `1.0.0`).\n- **Guidance:** Start at `1.0.0` for first publish. Bump `PATCH` for fixes, `MINOR` for new capabilities, `MAJOR` for breaking changes to config or behavior.\n\n### `author` (string)\n\nYour Web42 username. Set automatically by `web42 init` from your auth credentials.\n\n- **Constraints:** Non-empty string.\n- **Guidance:** Don't edit manually — it's populated from `web42 auth whoami`.\n\n## Optional Fields\n\n### `platform` (string)\n\nTarget agent platform.\n\n- **Values:** Currently only `\"openclaw\"`.\n- **Guidance:** Set during `web42 init` based on the platform prompt.\n\n### `skills` (array)\n\nList of skills the agent provides. Each entry has `name` (string) and `description` (string).\n\n- **Auto-detected** from `skills/*/SKILL.md` during init and pack.\n- **Guidance:** Don't edit manually. Add skills by creating `skills/<name>/SKILL.md` in your workspace. Internal skills (with `internal: true` in frontmatter) are automatically excluded.\n\n### `plugins` (string array)\n\nReserved for future use.\n\n- **Default:** `[]`\n- **Guidance:** Leave empty for now.\n\n### `modelPreferences` (object)\n\nPreferred LLM models for this agent.\n\n- **Fields:** `primary` (string, optional), `fallback` (string, optional)\n- **Example:** `{ \"primary\": \"claude-sonnet-4-20250514\" }`\n- **Guidance:** Set `primary` to the model the agent is designed and tested for. The `fallback` is used if the primary is unavailable. During install, the CLI will prompt buyers for the corresponding provider API key.\n\n### `tags` (string array)\n\nSearchable labels for marketplace discoverability.\n\n- **Default:** `[]`\n- **Good:** `[\"support\", \"crm\", \"slack\", \"weekly-reports\"]`\n- **Bad:** `[\"ai\", \"agent\", \"good\"]` (too generic)\n- **Guidance:** 3–6 tags. Think about what a buyer would search for. Mix category terms (\"support\", \"finance\") with capability terms (\"slack-integration\", \"pdf-generation\").\n- **Note:** Tags are also specified in `.web42/marketplace.json`. The marketplace.json tags are the canonical source that gets synced to the remote. If tags exist in both files, the marketplace.json values take precedence during sync. See `references/marketplace-config.md`.\n\n### `coverImage` (string)\n\nPath to a cover image file, relative to workspace root.\n\n- **Guidance:** Optional. A good cover image dramatically improves click-through on the marketplace. Use a 1200x630 or 1200x1200 image.\n- **Note:** For the marketplace listing, the primary visual asset is now the agent avatar at `.web42/avatar.*` and resources in `.web42/resources/`. The `coverImage` manifest field is still supported for backward compatibility but resources are the preferred approach. See `references/resources-guide.md`.\n\n### `demoVideoUrl` (string)\n\nURL to a demo video.\n\n- **Constraints:** Must be a valid URL.\n- **Guidance:** A 1–3 minute video showing the agent in action converts far better than text alone. Host on YouTube, Loom, or similar.\n- **Note:** Demo videos can also be managed as resources in `.web42/resources/` with type `\"video\"`. Resources are uploaded directly to the marketplace. Use `demoVideoUrl` for externally hosted videos (YouTube, Loom) or `.web42/resources/` for self-hosted files. See `references/resources-guide.md`.\n\n### `configVariables` (array)\n\nSecrets and configuration values that buyers provide during install.\n\n- **Each entry:** `{ key, label, description?, required, default? }`\n - `key` — Environment variable name (e.g., `SLACK_BOT_TOKEN`)\n - `label` — Human-readable name shown in the install prompt (e.g., \"Slack Bot Token\")\n - `description` — Optional help text explaining where to find this value\n - `required` — Whether install should block without it\n - `default` — Optional default value\n- **Auto-detected** from skill files during pack (secrets are stripped and replaced with placeholders).\n- **Guidance:** For each config variable, make the `label` and `description` crystal clear. A buyer who has never seen your agent should understand exactly what to provide and where to get it.\n\n## Example Manifest\n\n```json\n{\n \"format\": \"agentpkg/1\",\n \"platform\": \"openclaw\",\n \"name\": \"weekly-digest\",\n \"description\": \"Summarizes your team's CRM activity and posts a digest to Slack every Monday morning.\",\n \"version\": \"1.0.0\",\n \"author\": \"alice\",\n \"skills\": [\n { \"name\": \"crm-reader\", \"description\": \"Query CRM data for weekly activity\" },\n { \"name\": \"slack-poster\", \"description\": \"Post formatted messages to Slack channels\" }\n ],\n \"plugins\": [],\n \"modelPreferences\": { \"primary\": \"claude-sonnet-4-20250514\" },\n \"tags\": [\"crm\", \"slack\", \"weekly-reports\", \"productivity\"],\n \"coverImage\": \"assets/cover.png\",\n \"demoVideoUrl\": \"https://www.youtube.com/watch?v=example\",\n \"configVariables\": [\n {\n \"key\": \"CRM_API_KEY\",\n \"label\": \"CRM API Key\",\n \"description\": \"Found in your CRM dashboard under Settings > API\",\n \"required\": true\n },\n {\n \"key\": \"SLACK_BOT_TOKEN\",\n \"label\": \"Slack Bot Token\",\n \"description\": \"Create a Slack app at api.slack.com and copy the Bot User OAuth Token\",\n \"required\": true\n }\n ]\n}\n```\n",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
path: "references/marketplace-config.md",
|
|
24
|
+
content: "# Marketplace Configuration Reference\n\nThe file `.web42/marketplace.json` controls how your agent appears and is sold on the Web42 marketplace. It is created automatically by `web42 init` with sensible defaults.\n\n## File Location\n\n```\n.web42/marketplace.json\n```\n\n## Fields\n\n### `price_cents` (number)\n\nThe price in cents. `0` means free.\n\n- **Default:** `0`\n- **Examples:** `0` (free), `500` ($5.00), `2999` ($29.99), `10000` ($100.00)\n- **Guidance:**\n - Free agents get more installs but less revenue. Consider free for simple utilities, paid for specialized workflows.\n - Look at comparable agents on the marketplace for pricing cues.\n - $5–$15 is a sweet spot for productivity agents. $20–$50 for specialized professional tools.\n - You can always start free and add pricing later.\n\n### `currency` (string)\n\nISO 4217 currency code.\n\n- **Default:** `\"usd\"`\n- **Values:** Currently only `\"usd\"` is supported.\n\n### `license` (string | null)\n\nThe license under which the agent is distributed. `null` means no license specified.\n\n- **Default:** `null`\n- **Supported values:**\n\n| License | Summary | Best For |\n|---------|---------|----------|\n| `\"MIT\"` | Permissive. Buyers can do almost anything. | Open tools, community agents |\n| `\"Apache-2.0\"` | Permissive + patent grant. | Enterprise-friendly tools |\n| `\"GPL-3.0\"` | Copyleft. Derivatives must also be GPL. | Agents you want to stay open |\n| `\"BSD-3-Clause\"` | Permissive, similar to MIT. | Academic or research agents |\n| `\"Proprietary\"` | All rights reserved. No redistribution. | Commercial/paid agents |\n| `\"Custom\"` | Custom terms defined elsewhere. | Unique licensing needs |\n\n- **Guidance:**\n - For **free agents** intended as community contributions: `MIT` or `Apache-2.0`.\n - For **paid agents**: `Proprietary` is the standard choice — buyers get usage rights but cannot redistribute.\n - If unsure, `MIT` for free and `Proprietary` for paid is a safe default.\n\n### `tags` (string array)\n\nSearchable labels for marketplace discoverability. These are the canonical tags shown on the marketplace listing.\n\n- **Default:** `[]`\n- **Constraints:** Each tag should be lowercase, hyphenated for multi-word.\n- **Good:** `[\"crm\", \"slack-integration\", \"weekly-reports\", \"productivity\"]`\n- **Bad:** `[\"ai\", \"agent\", \"good\", \"cool\"]` (too generic)\n- **Guidance:**\n - Use 3–6 tags.\n - Mix **category terms** (\"finance\", \"devops\", \"support\") with **capability terms** (\"pdf-generation\", \"slack-integration\", \"email-monitoring\").\n - Think about what a buyer would search for to find your agent.\n - Tags also appear in the manifest — the marketplace.json tags are the canonical source that gets synced to the remote.\n\n## Visibility (Dashboard Only)\n\nAgent visibility is **not** controlled through local files. It is managed exclusively through the Web42 dashboard at `web42.ai`.\n\nThe visibility lifecycle:\n\n1. **`private`** (default) — Only you can see it. Use this while developing and preparing.\n2. **`unlisted`** — Accessible via direct link but not in search/browse. Good for beta testers or early feedback.\n3. **`public`** — Visible to everyone on the marketplace. Set this when you're ready to launch.\n\nRemind the user to visit the dashboard to toggle visibility when the agent is ready.\n\n## Example File\n\n```json\n{\n \"price_cents\": 999,\n \"currency\": \"usd\",\n \"license\": \"Proprietary\",\n \"tags\": [\n \"crm\",\n \"slack-integration\",\n \"weekly-reports\",\n \"productivity\"\n ]\n}\n```\n\n## Sync Behavior\n\nWhen you run `web42 push`, the contents of `.web42/marketplace.json` are included in the sync snapshot and written to the remote database. When you run `web42 pull`, remote marketplace settings (except visibility) are written back to this file.\n\nChanges made on the dashboard (e.g., editing tags or price via the web UI) will be reflected locally on the next `web42 pull`.\n",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
path: "references/resources-guide.md",
|
|
28
|
+
content: "# Resources Guide\n\nResources are the visual media and documents that accompany your agent's marketplace listing: screenshots, demo videos, architecture diagrams, PDF guides, etc. They make listings dramatically more compelling.\n\n## File Locations\n\n```\n.web42/resources.json # Metadata describing each resource\n.web42/resources/ # The actual resource files\n screenshot-dashboard.png\n demo-recording.mp4\n setup-guide.pdf\n```\n\n## `resources.json` Schema\n\nThe file is a JSON array of `ResourceMeta` objects:\n\n```json\n[\n {\n \"file\": \"screenshot-dashboard.png\",\n \"title\": \"Dashboard Overview\",\n \"description\": \"The main dashboard showing weekly report generation\",\n \"type\": \"image\",\n \"sort_order\": 0\n },\n {\n \"file\": \"demo-recording.mp4\",\n \"title\": \"3-Minute Demo\",\n \"description\": \"Watch the agent draft a report from CRM data in real time\",\n \"type\": \"video\",\n \"sort_order\": 1\n }\n]\n```\n\n### Fields\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `file` | string | Yes | Filename in `.web42/resources/` |\n| `title` | string | Yes | Display title on the marketplace listing |\n| `description` | string | No | Optional caption or context |\n| `type` | `\"image\"` \\| `\"video\"` \\| `\"document\"` | Yes | Determines how the marketplace renders it |\n| `sort_order` | number | Yes | Display order (0 = first) |\n\n## Resource Types\n\n### Images\n\nScreenshots, diagrams, architecture overviews, result samples.\n\n- **Recommended:** 1200x800 or 1600x900 (16:9 landscape)\n- **Formats:** PNG, JPEG, WebP\n- **Max size:** 5 MB per file\n- **Tips:**\n - Lead with your best screenshot — it appears first in the gallery.\n - Show the agent *in action*, not just a static interface.\n - Annotate screenshots with callouts if key features are not obvious.\n - Dark-mode and light-mode variants both work well.\n\n### Videos\n\nDemo recordings, walkthroughs, setup tutorials.\n\n- **Recommended:** 1–3 minutes for demos, under 60 seconds for teasers\n- **Formats:** MP4, WebM\n- **Max size:** 50 MB per file (for local storage; consider hosting large videos externally)\n- **Tips:**\n - Start with the outcome, not the setup. Show the result in the first 10 seconds.\n - Screen recordings with voiceover convert better than silent ones.\n - For large video files, consider hosting on YouTube/Loom and linking via `demoVideoUrl` in the manifest instead.\n\n### Documents\n\nPDF guides, setup instructions, architecture docs.\n\n- **Formats:** PDF\n- **Max size:** 10 MB per file\n- **Tips:**\n - Use for detailed setup guides that are too long for the README.\n - A 1-page \"quick start\" PDF is a nice touch for complex agents.\n\n## How Resources Appear on the Marketplace\n\nResources are displayed on the agent's detail page:\n\n- **Images** show as a scrollable gallery below the agent header.\n- **Videos** embed with a play button.\n- **Documents** appear as downloadable links.\n\nThe `sort_order` controls the display sequence across all types.\n\n## Sync Behavior\n\nWhen you run `web42 push`, the CLI:\n\n1. Reads `.web42/resources.json` for metadata.\n2. Uploads each file from `.web42/resources/` to the server.\n3. Creates the corresponding `agent_resources` rows in the database.\n\nWhen you run `web42 pull`, the CLI writes `.web42/resources.json` with metadata from the remote. Resource files themselves are not downloaded back (they are referenced by URL in the snapshot).\n\n## Example Workflow\n\n1. Take screenshots of your agent in action.\n2. Save them to `.web42/resources/`.\n3. Create or update `.web42/resources.json` with metadata for each file.\n4. Run `web42 push` — the resources upload alongside everything else.\n\n```json\n[\n {\n \"file\": \"slack-report.png\",\n \"title\": \"Weekly Report in Slack\",\n \"description\": \"Automated report posted to #team-updates every Monday\",\n \"type\": \"image\",\n \"sort_order\": 0\n },\n {\n \"file\": \"crm-dashboard.png\",\n \"title\": \"CRM Data View\",\n \"description\": \"The agent reads from your CRM and extracts key metrics\",\n \"type\": \"image\",\n \"sort_order\": 1\n },\n {\n \"file\": \"setup-guide.pdf\",\n \"title\": \"Setup Guide\",\n \"description\": \"Step-by-step guide for connecting your CRM and Slack\",\n \"type\": \"document\",\n \"sort_order\": 2\n }\n]\n```\n",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
path: "references/web42-folder.md",
|
|
32
|
+
content: "# The `.web42/` Folder\n\nThe `.web42/` directory in your agent workspace is the metadata and sync hub for the Web42 marketplace. It is created automatically by `web42 init`.\n\n## Structure\n\n```\n.web42/\n├── marketplace.json # Pricing, license, tags\n├── resources.json # Metadata for resource files\n├── sync.json # Sync state (auto-managed, do not edit)\n├── avatar.png # Agent profile image (optional)\n├── resources/ # Screenshots, videos, documents\n│ ├── screenshot-1.png\n│ └── demo.mp4\n└── dist/ # Pack output (auto-generated by web42 pack)\n ├── AGENTS.md\n ├── IDENTITY.md\n ├── manifest.json\n └── ...\n```\n\n## Files You Edit\n\n### `marketplace.json`\n\nControls pricing, licensing, and discoverability on the marketplace.\n\n- Created by `web42 init` with defaults.\n- Edit manually or with agent assistance.\n- Synced to/from the remote on push/pull.\n- See `references/marketplace-config.md` for the full field reference.\n\n### `resources.json`\n\nDescribes the resource files (screenshots, videos, documents) in the `resources/` subdirectory.\n\n- JSON array of `ResourceMeta` objects.\n- Each entry maps a file in `resources/` to a title, description, type, and display order.\n- See `references/resources-guide.md` for the schema and guidance.\n\n### `avatar.{png,jpg,jpeg,webp,svg}`\n\nThe agent's profile image, shown on the marketplace listing and search results.\n\n- Only one avatar file should exist (the CLI picks the first match by extension priority: png, jpg, jpeg, webp, svg).\n- Recommended: 400x400 or larger, square aspect ratio.\n- Uploaded to the server on `web42 push`.\n\n### `resources/`\n\nDirectory containing the actual resource files referenced by `resources.json`.\n\n- Drop images, videos, or PDFs here.\n- Filenames must match the `file` field in `resources.json`.\n\n## Files You Should NOT Edit\n\n### `sync.json`\n\nTracks the sync state between your local workspace and the remote database.\n\n```json\n{\n \"agent_id\": \"0c4cc49e-...\",\n \"last_remote_hash\": \"7b1d3ecf...\",\n \"last_local_hash\": \"d9a10b8a...\",\n \"synced_at\": \"2026-03-17T03:54:46.124Z\"\n}\n```\n\n- **Auto-managed** by `web42 push`, `web42 pull`, and `web42 sync`.\n- Editing this file manually will break change detection.\n- Safe to delete if you want to force a full re-sync (next push/pull will recreate it).\n\n### `dist/`\n\nThe pack output directory, generated by `web42 pack` or automatically during `web42 push`.\n\n- Contains the processed, distributable version of your agent files.\n- **Auto-generated** — do not edit files here directly.\n- Excluded from the pack itself (no recursion).\n\n## Git Integration\n\nAdd `.web42/sync.json` and `.web42/dist/` to `.gitignore` since they are auto-generated:\n\n```gitignore\n.web42/sync.json\n.web42/dist/\n```\n\nKeep these in version control:\n\n- `.web42/marketplace.json`\n- `.web42/resources.json`\n- `.web42/avatar.*`\n- `.web42/resources/`\n\n## `.web42ignore` (Workspace Root)\n\nNot inside `.web42/` — lives at the workspace root alongside `manifest.json`.\n\n- Created by `web42 init` with sensible defaults (IDE dirs, env files, test folders, drafts).\n- Glob patterns, one per line. Lines starting with `#` are comments.\n- Controls which files are excluded when running `web42 pack` or `web42 push`.\n- Use `web42 pack --dry-run` to verify what gets included/excluded.\n- See `references/file-hygiene.md` for full details.\n\nKeep `.web42ignore` in version control so the ignore rules travel with the project.\n\n## Sync Lifecycle\n\n```\nweb42 init → Creates .web42/, marketplace.json, resources.json, .web42ignore\nweb42 pack → Generates .web42/dist/ from workspace files (respects .web42ignore)\nweb42 push → Sends snapshot (manifest + README + marketplace + files + avatar + resources) to remote\nweb42 pull → Fetches remote snapshot, writes to local files\nweb42 sync → Shows local vs remote hash comparison without changing anything\n```\n",
|
|
21
33
|
},
|
|
22
34
|
{
|
|
23
35
|
path: "SKILL.md",
|
|
24
|
-
content: "---\nname: web42-publish-prep\ndescription: \"This skill should be used when the user asks to 'prepare my agent for Web42', 'publish to Web42', 'set up web42 CLI', 'create a manifest', 'write an agent README', 'clean up files before pushing', 'init web42', or needs help packaging an agent project for the Web42 marketplace. Guides the full lifecycle from init through push-ready state.\"\ninternal: true\nmetadata:\n clawdbot:\n emoji: \"📦\"\n requires:\n anyBins: [\"web42\"]\n os: [\"linux\", \"darwin\", \"win32\"]\n---\n\n# Web42 Publish Prep\n\nPrepare an agent project for publishing to the Web42 marketplace. This skill covers the full lifecycle: initializing the project, populating the manifest, writing a compelling README, and auditing workspace files so only the right content ships to users.\n\n## When to Activate\n\nActivate when the user wants to get their agent ready for the Web42 marketplace — whether starting from scratch or cleaning up an existing project before push.\n\n## Prerequisites\n\n- The Web42 CLI must be installed (`npx web42-cli` or globally via `npm i -g web42-cli`).\n- The user must be authenticated (`web42 auth login`). Verify with `web42 auth whoami`.\n- The workspace must contain a supported platform config (currently OpenClaw — `openclaw.json`).\n\nIf any prerequisite is missing, guide the user through resolving it before proceeding.\n\n## Workflow\n\n### Phase 1 — Initialize the Project\n\nCheck whether `manifest.json` already exists in the workspace root.\n\n- **If missing:** Run `web42 init` interactively. The CLI prompts for platform, description, version, and detects skills from `skills/*/SKILL.md`.\n- **If present:** Read and validate the existing manifest against the field reference in `references/manifest-fields.md`. Report any missing or invalid fields.\n\nAfter init, verify that the scaffolded platform files exist (`AGENTS.md`, `IDENTITY.md`, `SOUL.md`, `TOOLS.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, `USER.md`). If the user already customized these, do not overwrite — just confirm they are present.\n\n### Phase 2 — Enrich the Manifest\n\nRead the current `manifest.json` and walk through each field with the user. Consult `references/manifest-fields.md` for the full field reference.\n\nKey actions:\n\n1. **`name`** — Confirm it is lowercase-hyphenated and reflects the agent's purpose. Suggest alternatives if generic.\n2. **`description`** — Must be 1–500 characters. Draft a concise, benefit-oriented description that tells a potential buyer what the agent *does for them*.\n3. **`version`** — Ensure semver format (`MAJOR.MINOR.PATCH`).\n4. **`tags`** — Suggest 3–6 relevant tags for discoverability.\n5. **`skills`** — Auto-detected from `skills/*/SKILL.md`. If none found, ask if skills should be documented.\n6. **`configVariables`** — For each detected secret/config, ensure `label` and `description` are clear enough for a buyer.\n7. **`modelPreferences`** — Set `primary` to the intended model. Optionally set a `fallback`.\n8. **`coverImage`** — Ask if the user has a cover image (path relative to workspace).\n9. **`demoVideoUrl`** — Ask if there is a demo video URL to include.\n\nWrite the updated `manifest.json` only after user confirmation.\n\n### Phase 3 — Write the README\n\nThe README is the storefront — the agent's pitch deck. Read `assets/readme-template.md` for inspiration, then write a README that lets the agent's personality shine.\n\nPrinciples:\n\n- **Lead with outcomes, not internals.** Paint the picture of life *with* this agent.\n- **Show personality.** Write in the agent's own voice — confident, creative, even playful.\n- **Use rich media.** GIFs, demo videos, screenshots, embedded links. The marketplace renders full Markdown.\n- **Give concrete scenarios.** \"Ask me to...\" or \"Imagine you need to...\" — make it visceral.\n- **Include practical info** (install command, required config) but don't let it dominate.\n- **Don't reveal the recipe.** Focus on outcomes, not system prompts or internal file structures.\n\nWrite to `README.md` at workspace root. If one already exists, show a diff and ask before overwriting.\n\n### Phase 4 — Audit Workspace Files\n\nBefore packing, scan the workspace for files that should not ship to buyers. Consult `references/file-hygiene.md` for the full checklist.\n\nCommon issues to flag:\n\n- **Personal data:** `USER.md`, `MEMORY.md`, `memory/` directory, `HEARTBEAT.md` with creator-specific tasks\n- **Secrets:** `.env`, `.env.local`, API keys hardcoded in files, `.web42.config.json`\n- **Development artifacts:** `node_modules/`, `.git/`, IDE configs, build outputs\n- **Platform junk:** `.DS_Store`, `Thumbs.db`, `__pycache__/`\n- **Overly personal SOUL.md or IDENTITY.md:** Suggest generalizing if they reference the creator rather than the agent persona\n\nFor each flagged item:\n\n1. Explain why it might be a problem.\n2. Ask the user whether to remove, reset to scaffold default, or keep it.\n3. If unsure, recommend `web42 pack --dry-run` to preview the bundle.\n\n### Phase 5 — Validate and Preview\n\nRun `web42 pack --dry-run` to show exactly what files will be included. Review together:\n\n- Confirm file count and total size are reasonable.\n- Verify no secrets leaked (the CLI strips known patterns, but manual review catches edge cases).\n- Ensure `README.md` is present (push reads it from workspace root).\n\nWhen clean, inform the user they can publish with `web42 push`. The agent is created **private** by default — remind them to toggle visibility on the marketplace when ready.\n\n## CLI Quick Reference\n\n| Command | Purpose |\n|---------|---------|\n| `web42 auth login` | Authenticate via GitHub OAuth |\n| `web42 auth whoami` | Check current auth status |\n| `web42 init` | Scaffold `manifest.json` + platform files |\n| `web42 pack --dry-run` | Preview packaged files without writing |\n| `web42 pack` | Bundle into `.web42/` directory |\n| `web42 push` | Pack (if needed) and upload to marketplace |\n| `web42 pull` | Fetch latest published files back locally |\n\n## Resources\n\n### References\n- **`references/manifest-fields.md`** — Complete manifest.json field reference with types, constraints, and guidance.\n- **`references/file-hygiene.md`** — Checklist of files and patterns to audit before packing.\n\n### Assets\n- **`assets/readme-template.md`** — Inspirational README template for the marketplace storefront.\n",
|
|
36
|
+
content: "---\nname: web42-publish-prep\ndescription: \"This skill should be used when the user asks to 'prepare my agent for Web42', 'publish to Web42', 'set up web42 CLI', 'create a manifest', 'write an agent README', 'set up marketplace pricing', 'add screenshots', 'clean up files before pushing', 'init web42', or needs help packaging an agent project for the Web42 marketplace. Guides the full lifecycle from init through push-ready state, including marketplace configuration, visual assets, and sync.\"\ninternal: true\nmetadata:\n clawdbot:\n emoji: \"📦\"\n requires:\n anyBins: [\"web42\"]\n os: [\"linux\", \"darwin\", \"win32\"]\n---\n\n# Web42 Publish Prep\n\nPrepare an agent project for publishing to the Web42 marketplace. This skill covers the full lifecycle: initializing the project, populating the manifest, configuring marketplace settings (pricing, license, tags), preparing visual assets (avatar, screenshots, demo media), writing a compelling README, auditing workspace files, and validating everything before push.\n\n## When to Activate\n\nActivate when the user wants to get their agent ready for the Web42 marketplace — whether starting from scratch or cleaning up an existing project before push.\n\n## Prerequisites\n\n- The Web42 CLI must be installed (`brew install web42` or via the install script).\n- The user must be authenticated (`web42 auth login`). Verify with `web42 auth whoami`.\n- The workspace must contain a supported platform config (currently OpenClaw — `openclaw.json`).\n\nIf any prerequisite is missing, guide the user through resolving it before proceeding.\n\n## Workflow\n\n### Phase 1 — Initialize the Project\n\nCheck whether `manifest.json` already exists in the workspace root.\n\n- **If missing:** Run `web42 init` interactively. The CLI prompts for platform, description, version, and detects skills from `skills/*/SKILL.md`. It also scaffolds the `.web42/` metadata folder with `marketplace.json` and `resources.json`.\n- **If present:** Read and validate the existing manifest against the field reference in `references/manifest-fields.md`. Report any missing or invalid fields.\n\nAfter init, verify that these exist:\n\n1. **Platform files:** `AGENTS.md`, `IDENTITY.md`, `SOUL.md`, `TOOLS.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, `USER.md` — if the user already customized these, do not overwrite.\n2. **`.web42/` folder:** `marketplace.json`, `resources.json`, `resources/` directory. See `references/web42-folder.md` for the complete structure.\n\n### Phase 2 — Enrich the Manifest\n\nRead the current `manifest.json` and walk through each field with the user. Consult `references/manifest-fields.md` for the full field reference.\n\nKey actions:\n\n1. **`name`** — Confirm it is lowercase-hyphenated and reflects the agent's purpose. Suggest alternatives if generic.\n2. **`description`** — Must be 1–500 characters. Draft a concise, benefit-oriented description that tells a potential buyer what the agent *does for them*.\n3. **`version`** — Ensure semver format (`MAJOR.MINOR.PATCH`).\n4. **`skills`** — Auto-detected from `skills/*/SKILL.md`. If none found, ask if skills should be documented.\n5. **`configVariables`** — For each detected secret/config, ensure `label` and `description` are clear enough for a buyer.\n6. **`modelPreferences`** — Set `primary` to the intended model. Optionally set a `fallback`.\n\nWrite the updated `manifest.json` only after user confirmation.\n\n### Phase 3 — Configure Marketplace Settings\n\nRead `.web42/marketplace.json` and walk through each field. Consult `references/marketplace-config.md` for the full reference.\n\nKey actions:\n\n1. **`price_cents`** — Ask the user about their pricing strategy. Free (`0`) or paid? For paid agents, suggest a price based on the agent's capabilities and target audience. Explain that pricing can be changed later.\n2. **`currency`** — Currently only `\"usd\"`. Confirm and leave as default.\n3. **`license`** — Help choose. For free agents: suggest `\"MIT\"` or `\"Apache-2.0\"`. For paid agents: suggest `\"Proprietary\"`. Explain the implications briefly.\n4. **`tags`** — Suggest 3–6 searchable tags. Mix category terms (\"finance\", \"devops\") with capability terms (\"slack-integration\", \"pdf-generation\"). Think about what a buyer would search for.\n\nWrite `.web42/marketplace.json` only after user confirmation.\n\n**Important:** Visibility (`public`/`private`/`unlisted`) is managed exclusively through the Web42 dashboard, not through local files. Remind the user that the agent starts private and they should toggle visibility on the dashboard when ready to launch.\n\n### Phase 4 — Prepare Visual Assets\n\nVisual assets are what make a marketplace listing stand out. Walk through each:\n\n#### Avatar\n\nCheck if `.web42/avatar.{png,jpg,webp,svg}` exists.\n\n- If missing, ask the user if they want to provide or generate one.\n- **Recommended:** 400x400 or larger, square, PNG or WebP.\n- The avatar appears on the marketplace listing, search results, and the agent's profile.\n- If the user wants to generate one, help create a prompt that captures the agent's personality and purpose.\n\n#### Resources (Screenshots, Videos, Documents)\n\nCheck `.web42/resources.json` and `.web42/resources/`. Consult `references/resources-guide.md`.\n\n- **Screenshots** — The single most impactful asset. Ask the user to capture 2–4 screenshots showing the agent in action. Recommend 1200x800 or 1600x900 (landscape).\n- **Demo video** — A 1–3 minute recording showing the agent's core workflow. Dramatically improves conversion. Can be a screen recording with voiceover.\n- **Documents** — Optional setup guides or architecture overviews as PDF.\n\nFor each resource:\n\n1. Help the user save files to `.web42/resources/`.\n2. Create or update `.web42/resources.json` with metadata (`file`, `title`, `description`, `type`, `sort_order`).\n3. Put the strongest visual first (`sort_order: 0`).\n\n### Phase 5 — Write the README\n\nThe README is the storefront — the agent's pitch deck. Read `assets/readme-template.md` for inspiration, then write a README that lets the agent's personality shine.\n\nPrinciples:\n\n- **Lead with outcomes, not internals.** Paint the picture of life *with* this agent.\n- **Show personality.** Write in the agent's own voice — confident, creative, even playful.\n- **Use rich media.** Reference screenshots from `.web42/resources/`, embed demo videos, include links. The marketplace renders full Markdown.\n- **Give concrete scenarios.** \"Ask me to...\" or \"Imagine you need to...\" — make it visceral.\n- **Include practical info** (install command, required config) but don't let it dominate.\n- **Don't reveal the recipe.** Focus on outcomes, not system prompts or internal file structures.\n\nWrite to `README.md` at workspace root. If one already exists, show a diff and ask before overwriting.\n\n### Phase 6 — Audit Workspace Files\n\nBefore packing, scan the workspace for files that should not ship to buyers. Consult `references/file-hygiene.md` for the full checklist.\n\nCommon issues to flag:\n\n- **Personal data:** `USER.md`, `MEMORY.md`, `memory/` directory, `HEARTBEAT.md` with creator-specific tasks\n- **Secrets:** `.env`, `.env.local`, API keys hardcoded in files, `.web42.config.json`\n- **Development artifacts:** `node_modules/`, `.git/`, IDE configs, build outputs\n- **Platform junk:** `.DS_Store`, `Thumbs.db`, `__pycache__/`\n- **Overly personal SOUL.md or IDENTITY.md:** Suggest generalizing if they reference the creator rather than the agent persona\n\nFor each flagged item:\n\n1. Explain why it might be a problem.\n2. Ask the user whether to remove, reset to scaffold default, or keep it.\n3. If unsure, recommend `web42 pack --dry-run` to preview the bundle.\n\n### Phase 7 — Validate, Pack, and Sync\n\nRun `web42 pack --dry-run` to show exactly what files will be included in `.web42/dist/`. Review together:\n\n- Confirm file count and total size are reasonable.\n- Verify no secrets leaked (the CLI strips known patterns, but manual review catches edge cases).\n- Ensure `README.md` is present.\n- Ensure `.web42/marketplace.json` has pricing, license, and tags set.\n- Ensure at least one screenshot or resource exists in `.web42/resources/`.\n\nWhen clean, the user can publish:\n\n1. **`web42 push`** — Packs (if needed), pushes the full snapshot (manifest, README, marketplace config, files, avatar, resources) to the remote.\n2. **`web42 sync`** — Check sync status at any time to see if local and remote are aligned.\n3. **Dashboard** — Remind the user to visit `web42.ai` to set visibility to `public` or `unlisted` when ready.\n\nAfter the first push, subsequent changes follow the sync workflow:\n\n- Edit locally → `web42 push` to sync up\n- Edit on dashboard → `web42 pull` to sync down\n- `web42 sync` to check status without changing anything\n- `--force` flag on push/pull to override when both sides have changed\n\n## CLI Quick Reference\n\n| Command | Purpose |\n|---------|---------|\n| `web42 auth login` | Authenticate via GitHub OAuth |\n| `web42 auth whoami` | Check current auth status |\n| `web42 init` | Scaffold `manifest.json` + `.web42/` metadata folder |\n| `web42 pack --dry-run` | Preview packaged files without writing |\n| `web42 pack` | Bundle workspace into `.web42/dist/` |\n| `web42 push` | Pack (if needed) and sync everything to the marketplace |\n| `web42 push --force` | Push even if no local changes detected |\n| `web42 pull` | Fetch latest state from the marketplace to local files |\n| `web42 pull --force` | Pull even if no remote changes detected |\n| `web42 sync` | Show sync status (local vs remote hash comparison) |\n\n## Resources\n\n### References\n- **`references/web42-folder.md`** — Complete `.web42/` folder structure reference.\n- **`references/manifest-fields.md`** — `manifest.json` field reference with types, constraints, and guidance.\n- **`references/marketplace-config.md`** — `.web42/marketplace.json` field reference with pricing and license guidance.\n- **`references/resources-guide.md`** — Resource types, schema, dimensions, and best practices for screenshots/videos/docs.\n- **`references/file-hygiene.md`** — Checklist of files and patterns to audit before packing.\n\n### Assets\n- **`assets/readme-template.md`** — Inspirational README template for the marketplace storefront.\n",
|
|
25
37
|
},
|
|
26
38
|
],
|
|
27
39
|
},
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { pushCommand } from "./commands/push.js";
|
|
|
8
8
|
import { pullCommand } from "./commands/pull.js";
|
|
9
9
|
import { remixCommand } from "./commands/remix.js";
|
|
10
10
|
import { searchCommand } from "./commands/search.js";
|
|
11
|
+
import { syncCommand } from "./commands/sync.js";
|
|
11
12
|
import { getAllPlatformCommands } from "./platforms/registry.js";
|
|
12
13
|
import { setApiUrl } from "./utils/config.js";
|
|
13
14
|
import { CLI_VERSION } from "./version.js";
|
|
@@ -31,6 +32,7 @@ program.addCommand(pushCommand);
|
|
|
31
32
|
program.addCommand(pullCommand);
|
|
32
33
|
program.addCommand(remixCommand);
|
|
33
34
|
program.addCommand(searchCommand);
|
|
35
|
+
program.addCommand(syncCommand);
|
|
34
36
|
for (const platformCmd of getAllPlatformCommands()) {
|
|
35
37
|
program.addCommand(platformCmd);
|
|
36
38
|
}
|
package/dist/platforms/base.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { InitConfig, InstalledAgent, InstallOptions, InstallResult, PackOptions, PackResult, PlatformAdapter, UninstallOptions, UninstallResult } from "../base.js";
|
|
2
|
+
export declare const HARDCODED_EXCLUDES: string[];
|
|
2
3
|
export declare class OpenClawAdapter implements PlatformAdapter {
|
|
3
4
|
name: string;
|
|
4
5
|
home: string;
|
|
@@ -7,7 +7,7 @@ import { stripSecrets, stripChannelSecrets } from "../../utils/secrets.js";
|
|
|
7
7
|
import { USER_MD } from "./templates.js";
|
|
8
8
|
const OPENCLAW_HOME = join(homedir(), ".openclaw");
|
|
9
9
|
const OPENCLAW_CONFIG_PATH = join(OPENCLAW_HOME, "openclaw.json");
|
|
10
|
-
const HARDCODED_EXCLUDES = [
|
|
10
|
+
export const HARDCODED_EXCLUDES = [
|
|
11
11
|
"auth-profiles.json",
|
|
12
12
|
"MEMORY.md",
|
|
13
13
|
"memory/**",
|
|
@@ -411,7 +411,7 @@ export class OpenClawAdapter {
|
|
|
411
411
|
configTemplate = extraction.configTemplate;
|
|
412
412
|
configVariables = extraction.configVariables;
|
|
413
413
|
}
|
|
414
|
-
return { files, configTemplate, configVariables };
|
|
414
|
+
return { files, configTemplate, configVariables, ignorePatterns };
|
|
415
415
|
}
|
|
416
416
|
async install(options) {
|
|
417
417
|
const { agentSlug, username, workspacePath, files, configTemplate, configAnswers, } = options;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export interface AgentSnapshot {
|
|
2
|
+
identity: {
|
|
3
|
+
name: string;
|
|
4
|
+
slug: string;
|
|
5
|
+
description: string;
|
|
6
|
+
};
|
|
7
|
+
readme: string;
|
|
8
|
+
manifest: Record<string, unknown>;
|
|
9
|
+
marketplace: {
|
|
10
|
+
price_cents: number;
|
|
11
|
+
currency: string;
|
|
12
|
+
license: string | null;
|
|
13
|
+
visibility: string;
|
|
14
|
+
tags: string[];
|
|
15
|
+
};
|
|
16
|
+
avatar_url: string | null;
|
|
17
|
+
resources: Array<{
|
|
18
|
+
title: string;
|
|
19
|
+
description: string | null;
|
|
20
|
+
type: string;
|
|
21
|
+
url: string;
|
|
22
|
+
thumbnail_url: string | null;
|
|
23
|
+
sort_order: number;
|
|
24
|
+
}>;
|
|
25
|
+
files: Array<{
|
|
26
|
+
path: string;
|
|
27
|
+
content: string | null;
|
|
28
|
+
content_hash: string;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
export interface SyncStatusResponse {
|
|
32
|
+
hash: string;
|
|
33
|
+
updated_at: string;
|
|
34
|
+
}
|
|
35
|
+
export interface SyncPushResponse {
|
|
36
|
+
hash: string;
|
|
37
|
+
updated_at: string;
|
|
38
|
+
}
|
|
39
|
+
export interface SyncPullResponse {
|
|
40
|
+
hash: string;
|
|
41
|
+
updated_at: string;
|
|
42
|
+
snapshot: AgentSnapshot;
|
|
43
|
+
}
|
|
44
|
+
export interface AvatarUploadResponse {
|
|
45
|
+
avatar_url: string | null;
|
|
46
|
+
hash: string;
|
|
47
|
+
updated_at: string;
|
|
48
|
+
}
|
|
49
|
+
export interface ResourcesUploadResponse {
|
|
50
|
+
resources: Array<Record<string, unknown>>;
|
|
51
|
+
hash: string;
|
|
52
|
+
updated_at: string;
|
|
53
|
+
}
|
|
54
|
+
export interface SyncState {
|
|
55
|
+
agent_id: string;
|
|
56
|
+
last_remote_hash: string;
|
|
57
|
+
last_local_hash: string;
|
|
58
|
+
synced_at: string;
|
|
59
|
+
}
|
|
60
|
+
export interface MarketplaceConfig {
|
|
61
|
+
price_cents: number;
|
|
62
|
+
currency: string;
|
|
63
|
+
license: string | null;
|
|
64
|
+
visibility: string;
|
|
65
|
+
tags: string[];
|
|
66
|
+
}
|
|
67
|
+
export interface ResourceMeta {
|
|
68
|
+
file: string;
|
|
69
|
+
title: string;
|
|
70
|
+
description?: string;
|
|
71
|
+
type: "video" | "image" | "document";
|
|
72
|
+
sort_order: number;
|
|
73
|
+
}
|
|
74
|
+
export declare const DEFAULT_MARKETPLACE: MarketplaceConfig;
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export declare function apiRequest(path: string, options?: RequestInit): Promise<Response>;
|
|
2
2
|
export declare function apiGet<T>(path: string): Promise<T>;
|
|
3
3
|
export declare function apiPost<T>(path: string, data: unknown): Promise<T>;
|
|
4
|
+
export declare function apiDelete<T>(path: string): Promise<T>;
|
|
5
|
+
export declare function apiFormData<T>(path: string, formData: FormData): Promise<T>;
|
package/dist/utils/api.js
CHANGED
|
@@ -33,3 +33,29 @@ export async function apiPost(path, data) {
|
|
|
33
33
|
}
|
|
34
34
|
return res.json();
|
|
35
35
|
}
|
|
36
|
+
export async function apiDelete(path) {
|
|
37
|
+
const res = await apiRequest(path, { method: "DELETE" });
|
|
38
|
+
if (!res.ok) {
|
|
39
|
+
const body = await res.json().catch(() => ({}));
|
|
40
|
+
throw new Error(body.error || `API error: ${res.status}`);
|
|
41
|
+
}
|
|
42
|
+
return res.json();
|
|
43
|
+
}
|
|
44
|
+
export async function apiFormData(path, formData) {
|
|
45
|
+
const config = getConfig();
|
|
46
|
+
const url = `${config.apiUrl}${path}`;
|
|
47
|
+
const headers = {};
|
|
48
|
+
if (config.token) {
|
|
49
|
+
headers["Authorization"] = `Bearer ${config.token}`;
|
|
50
|
+
}
|
|
51
|
+
const res = await fetch(url, {
|
|
52
|
+
method: "POST",
|
|
53
|
+
headers,
|
|
54
|
+
body: formData,
|
|
55
|
+
});
|
|
56
|
+
if (!res.ok) {
|
|
57
|
+
const body = await res.json().catch(() => ({}));
|
|
58
|
+
throw new Error(body.error || `API error: ${res.status}`);
|
|
59
|
+
}
|
|
60
|
+
return res.json();
|
|
61
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentSnapshot, MarketplaceConfig, ResourceMeta, SyncState } from "../types/sync.js";
|
|
2
|
+
export declare function sha256(input: string): string;
|
|
3
|
+
export declare function canonicalJson(obj: unknown): string;
|
|
4
|
+
export declare function computeHashFromSnapshot(snapshot: AgentSnapshot): string;
|
|
5
|
+
export declare function readSyncState(cwd: string): SyncState | null;
|
|
6
|
+
export declare function writeSyncState(cwd: string, state: SyncState): void;
|
|
7
|
+
export declare function readMarketplace(cwd: string): MarketplaceConfig;
|
|
8
|
+
export declare function writeMarketplace(cwd: string, data: MarketplaceConfig): void;
|
|
9
|
+
export declare function findLocalAvatar(cwd: string): string | null;
|
|
10
|
+
export declare function readResourcesMeta(cwd: string): ResourceMeta[];
|
|
11
|
+
export declare function writeResourcesMeta(cwd: string, meta: ResourceMeta[]): void;
|
|
12
|
+
export declare function buildLocalSnapshot(cwd: string): AgentSnapshot;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { createHash } from "crypto";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, } from "fs";
|
|
3
|
+
import { join, relative } from "path";
|
|
4
|
+
const AVATAR_EXTENSIONS = ["png", "jpg", "jpeg", "webp", "svg"];
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Hash functions -- exact mirror of lib/sync/agent-sync.ts
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
export function sha256(input) {
|
|
9
|
+
return createHash("sha256").update(input, "utf-8").digest("hex");
|
|
10
|
+
}
|
|
11
|
+
export function canonicalJson(obj) {
|
|
12
|
+
return JSON.stringify(obj, (_key, value) => {
|
|
13
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
14
|
+
const sorted = {};
|
|
15
|
+
for (const k of Object.keys(value).sort()) {
|
|
16
|
+
sorted[k] = value[k];
|
|
17
|
+
}
|
|
18
|
+
return sorted;
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export function computeHashFromSnapshot(snapshot) {
|
|
24
|
+
const parts = [
|
|
25
|
+
canonicalJson(snapshot.identity),
|
|
26
|
+
snapshot.readme,
|
|
27
|
+
canonicalJson(snapshot.manifest),
|
|
28
|
+
canonicalJson(snapshot.marketplace),
|
|
29
|
+
snapshot.avatar_url ?? "",
|
|
30
|
+
canonicalJson(snapshot.resources
|
|
31
|
+
.slice()
|
|
32
|
+
.sort((a, b) => a.sort_order - b.sort_order)
|
|
33
|
+
.map((r) => ({
|
|
34
|
+
description: r.description,
|
|
35
|
+
sort_order: r.sort_order,
|
|
36
|
+
thumbnail_url: r.thumbnail_url,
|
|
37
|
+
title: r.title,
|
|
38
|
+
type: r.type,
|
|
39
|
+
url: r.url,
|
|
40
|
+
}))),
|
|
41
|
+
snapshot.files
|
|
42
|
+
.slice()
|
|
43
|
+
.sort((a, b) => a.path.localeCompare(b.path))
|
|
44
|
+
.map((f) => f.content_hash)
|
|
45
|
+
.join("|"),
|
|
46
|
+
];
|
|
47
|
+
return sha256(parts.join("\x00"));
|
|
48
|
+
}
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// .web42/sync.json
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
export function readSyncState(cwd) {
|
|
53
|
+
const p = join(cwd, ".web42", "sync.json");
|
|
54
|
+
if (!existsSync(p))
|
|
55
|
+
return null;
|
|
56
|
+
try {
|
|
57
|
+
return JSON.parse(readFileSync(p, "utf-8"));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function writeSyncState(cwd, state) {
|
|
64
|
+
const dir = join(cwd, ".web42");
|
|
65
|
+
mkdirSync(dir, { recursive: true });
|
|
66
|
+
writeFileSync(join(dir, "sync.json"), JSON.stringify(state, null, 2) + "\n");
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// .web42/marketplace.json
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
const MARKETPLACE_DEFAULTS = {
|
|
72
|
+
price_cents: 0,
|
|
73
|
+
currency: "usd",
|
|
74
|
+
license: null,
|
|
75
|
+
visibility: "private",
|
|
76
|
+
tags: [],
|
|
77
|
+
};
|
|
78
|
+
export function readMarketplace(cwd) {
|
|
79
|
+
const p = join(cwd, ".web42", "marketplace.json");
|
|
80
|
+
if (!existsSync(p))
|
|
81
|
+
return { ...MARKETPLACE_DEFAULTS };
|
|
82
|
+
try {
|
|
83
|
+
const raw = JSON.parse(readFileSync(p, "utf-8"));
|
|
84
|
+
return {
|
|
85
|
+
price_cents: raw.price_cents ?? MARKETPLACE_DEFAULTS.price_cents,
|
|
86
|
+
currency: raw.currency ?? MARKETPLACE_DEFAULTS.currency,
|
|
87
|
+
license: raw.license ?? MARKETPLACE_DEFAULTS.license,
|
|
88
|
+
visibility: raw.visibility ?? MARKETPLACE_DEFAULTS.visibility,
|
|
89
|
+
tags: Array.isArray(raw.tags) ? raw.tags : MARKETPLACE_DEFAULTS.tags,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return { ...MARKETPLACE_DEFAULTS };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export function writeMarketplace(cwd, data) {
|
|
97
|
+
const dir = join(cwd, ".web42");
|
|
98
|
+
mkdirSync(dir, { recursive: true });
|
|
99
|
+
writeFileSync(join(dir, "marketplace.json"), JSON.stringify(data, null, 2) + "\n");
|
|
100
|
+
}
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// .web42/avatar.*
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
export function findLocalAvatar(cwd) {
|
|
105
|
+
const dir = join(cwd, ".web42");
|
|
106
|
+
if (!existsSync(dir))
|
|
107
|
+
return null;
|
|
108
|
+
for (const ext of AVATAR_EXTENSIONS) {
|
|
109
|
+
const p = join(dir, `avatar.${ext}`);
|
|
110
|
+
if (existsSync(p))
|
|
111
|
+
return p;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// .web42/resources.json + .web42/resources/
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
export function readResourcesMeta(cwd) {
|
|
119
|
+
const p = join(cwd, ".web42", "resources.json");
|
|
120
|
+
if (!existsSync(p))
|
|
121
|
+
return [];
|
|
122
|
+
try {
|
|
123
|
+
const raw = JSON.parse(readFileSync(p, "utf-8"));
|
|
124
|
+
return Array.isArray(raw) ? raw : [];
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export function writeResourcesMeta(cwd, meta) {
|
|
131
|
+
const dir = join(cwd, ".web42");
|
|
132
|
+
mkdirSync(dir, { recursive: true });
|
|
133
|
+
writeFileSync(join(dir, "resources.json"), JSON.stringify(meta, null, 2) + "\n");
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// Read packed files from .web42/dist/
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
function readPackedFiles(dir) {
|
|
139
|
+
const files = [];
|
|
140
|
+
function walk(currentDir) {
|
|
141
|
+
const entries = readdirSync(currentDir, { withFileTypes: true });
|
|
142
|
+
for (const entry of entries) {
|
|
143
|
+
const fullPath = join(currentDir, entry.name);
|
|
144
|
+
if (entry.isDirectory()) {
|
|
145
|
+
walk(fullPath);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
if (entry.name === "manifest.json" && currentDir === dir)
|
|
149
|
+
continue;
|
|
150
|
+
const stat = statSync(fullPath);
|
|
151
|
+
if (stat.size > 1024 * 1024)
|
|
152
|
+
continue;
|
|
153
|
+
try {
|
|
154
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
155
|
+
const relPath = relative(dir, fullPath);
|
|
156
|
+
files.push({ path: relPath, content, content_hash: sha256(content) });
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// skip binary files
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (existsSync(dir))
|
|
165
|
+
walk(dir);
|
|
166
|
+
return files;
|
|
167
|
+
}
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// Build a full AgentSnapshot from local workspace
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
export function buildLocalSnapshot(cwd) {
|
|
172
|
+
const manifestPath = join(cwd, "manifest.json");
|
|
173
|
+
const manifest = existsSync(manifestPath)
|
|
174
|
+
? JSON.parse(readFileSync(manifestPath, "utf-8"))
|
|
175
|
+
: {};
|
|
176
|
+
const name = manifest.name ?? "";
|
|
177
|
+
const description = manifest.description ?? "";
|
|
178
|
+
const slug = name;
|
|
179
|
+
const readmePath = join(cwd, "README.md");
|
|
180
|
+
const readme = existsSync(readmePath)
|
|
181
|
+
? readFileSync(readmePath, "utf-8")
|
|
182
|
+
: "";
|
|
183
|
+
const marketplace = readMarketplace(cwd);
|
|
184
|
+
const avatarPath = findLocalAvatar(cwd);
|
|
185
|
+
const syncState = readSyncState(cwd);
|
|
186
|
+
const distDir = join(cwd, ".web42", "dist");
|
|
187
|
+
const files = readPackedFiles(distDir);
|
|
188
|
+
return {
|
|
189
|
+
identity: { name, slug, description },
|
|
190
|
+
readme,
|
|
191
|
+
manifest,
|
|
192
|
+
marketplace,
|
|
193
|
+
avatar_url: null,
|
|
194
|
+
resources: [],
|
|
195
|
+
files,
|
|
196
|
+
};
|
|
197
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.1.
|
|
1
|
+
export declare const CLI_VERSION = "0.1.8";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = "0.1.
|
|
1
|
+
export const CLI_VERSION = "0.1.8";
|