@web42/w42 0.1.4 → 0.1.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/LICENSE.md ADDED
@@ -0,0 +1,116 @@
1
+ # EULA (End User License Agreement)
2
+
3
+ ## Personal License
4
+
5
+ NewCult.co grants you an on-going, non-exclusive license to use this template.
6
+
7
+ The license grants permission to **one individual** (the Licensee) to access and use this template.
8
+
9
+ ### You **can**:
10
+
11
+ - Use this template to create unlimited End Products.
12
+ - Modify this template to create derivative components and templates. Those components and templates are subject to this license.
13
+ - Use this template to create unlimited End Products for unlimited clients.
14
+ - Use this template to create End Products where the End Product is sold to End Users.
15
+ - Use this template to create End Products that are open source and freely available to End Users.
16
+
17
+ ### You **cannot**:
18
+
19
+ - Use this template to create End Products that are designed to allow an End User to build their own End Products using this template or derivatives of this template.
20
+ - Re-distribute this template or derivatives of this template separately from an End Product, neither in code nor as design assets.
21
+ - Share your access to this template with any other individuals.
22
+ - Use this template to produce anything that may be deemed by NewCult.co, in their sole and absolute discretion, to be competitive or in conflict with the business of NewCult.co.
23
+
24
+ ### Example Usage
25
+
26
+ **Allowed** by the license:
27
+
28
+ - Creating a personal website by yourself.
29
+ - Creating a website or web application for a client that will be owned by that client.
30
+ - Creating a commercial SaaS application (like an invoicing app) where end users have to pay a fee to use the application.
31
+ - Creating a commercial self-hosted web application that is sold to end users for a one-time fee.
32
+ - Creating a web application that is free and open source, where the primary purpose is not to simply re-distribute the template and the source code is publicly available.
33
+
34
+ **Not allowed** by the license:
35
+
36
+ - Creating a repository of your favorite NewCult.co components or templates (or derivatives based on NewCult.co components or templates) and publishing it publicly.
37
+ - Creating a React or Vue version of NewCult.co and making it available either for sale or for free.
38
+ - Creating a Figma or Sketch UI kit based on the NewCult.co component designs.
39
+ - Creating a "website builder" project where end users can build their own websites using components or templates included with or derived from NewCult.co.
40
+ - Creating a theme, template, or project starter kit using the components or templates and making it available either for sale or for free.
41
+ - Creating an admin panel tool that is made available either for sale or for free.
42
+
43
+ In simple terms, use NewCult.co for anything you like as long as it doesn't compete with NewCult.co.
44
+
45
+ ### Personal License Definitions
46
+
47
+ - **Licensee**: The individual who has purchased a Personal License.
48
+ - **Components and Templates**: The source code and design assets made available to the Licensee after purchasing a NewCult.co license.
49
+ - **End Product**: Any artifact produced that incorporates the Components or Templates or derivatives of the Components or Templates.
50
+ - **End User**: A user of an End Product.
51
+ - **Client**: An individual or entity receiving custom professional services directly from the Licensee, produced specifically for that individual or entity. Customers of software-as-a-service products are not considered clients for the purpose of this document.
52
+
53
+ ## Team License
54
+
55
+ NewCult.co grants you an on-going, non-exclusive license to use this template.
56
+
57
+ The license grants permission for **up to 25 Employees and Contractors of the Licensee** to access and use this template.
58
+
59
+ ### You **can**:
60
+
61
+ - Use this template to create unlimited End Products.
62
+ - Modify this template to create derivative components and templates. Those components and templates are subject to this license.
63
+ - Use this template to create unlimited End Products for unlimited clients.
64
+ - Use this template to create End Products where the End Product is sold to End Users.
65
+ - Use this template to create End Products that are open source and freely available to End Users.
66
+
67
+ ### You **cannot**:
68
+
69
+ - Use the Components or Templates to create End Products that are designed to allow an End User to build their own End Products using the Components or Templates or derivatives of the Components or Templates.
70
+ - Re-distribute the Components or Templates or derivatives of the Components or Templates separately from an End Product.
71
+ - Use the Components or Templates to create End Products that are the property of any individual or entity other than the Licensee or clients of the Licensee.
72
+ - Use the Components or Templates to produce anything that may be deemed by NewCult.co, in their sole and absolute discretion, to be competitive or in conflict with the business of NewCult.co.
73
+
74
+ ### Example Usage
75
+
76
+ **Allowed** by the license:
77
+
78
+ - Creating a website for your company.
79
+ - Creating a website or web application for a client that will be owned by that client.
80
+ - Creating a commercial SaaS application (like an invoicing app) where end users have to pay a fee to use the application.
81
+ - Creating a commercial self-hosted web application that is sold to end users for a one-time fee.
82
+ - Creating a web application that is free and open source, where the primary purpose is not to simply re-distribute the components or templates and the source code is publicly available.
83
+
84
+ **Not allowed** by the license:
85
+
86
+ - Creating a repository of your favorite NewCult.co components or templates (or derivatives based on NewCult.co components or templates) and publishing it publicly.
87
+ - Creating a React or Vue version of NewCult.co and making it available either for sale or for free.
88
+ - Creating a "website builder" project where end users can build their own websites using components or templates included with or derived from NewCult.co.
89
+ - Creating a theme or template using the components or templates and making it available either for sale or for free.
90
+ - Creating any End Product that is not the sole property of either your company or a client of your company. For example, your employees/contractors can't use your company NewCult.co license to build their own websites or side projects.
91
+
92
+ ### Team License Definitions
93
+
94
+ - **Licensee**: The business entity who has purchased a Team License.
95
+ - **Components and Templates**: The source code and design assets made available to the Licensee after purchasing a NewCult.co license.
96
+ - **End Product**: Any artifact produced that incorporates the Components or Templates or derivatives of the Components or Templates.
97
+ - **End User**: A user of an End Product.
98
+ - **Employee**: A full-time or part-time employee of the Licensee.
99
+ - **Contractor**: An individual or business entity contracted to perform services for the Licensee.
100
+ - **Client**: An individual or entity receiving custom professional services directly from the Licensee, produced specifically for that individual or entity. Customers of software-as-a-service products are not considered clients for the purpose of this document.
101
+
102
+ ## Enforcement
103
+
104
+ If you are found to be in violation of the license, access to your NewCult.co account will be terminated, and a refund may be issued at our discretion. When license violation is blatant and malicious (such as intentionally redistributing the Components or Templates through private warez channels), no refund will be issued.
105
+
106
+ The copyright of this template is owned by NewCult.co. You are granted only the permissions described in this license; all other rights are reserved. NewCult.co reserves the right to pursue legal remedies for any unauthorized use of the Components or Templates outside the scope of this license.
107
+
108
+ ## Liability
109
+
110
+ NewCult.co’s liability to you for any costs, damages, or other losses arising from your use of the Components or Templates, including third-party claims against you, is limited to a refund of your license fee. NewCult.co is not liable for any consequential damages related to your use of the Components or Templates.
111
+
112
+ This Agreement is governed by the laws of the State of North Carolina, USA. Legal proceedings related to this Agreement may only be brought in the courts of North Carolina. You agree to service of process at the e-mail address on your original order.
113
+
114
+ ## Questions?
115
+
116
+ Unsure which license you need, or have questions about your use case? Contact us on Twitter at [x.com/nolansym](https://x.com/nolansym).
package/README.md CHANGED
@@ -1,73 +1,101 @@
1
1
  # @web42/cli
2
2
 
3
- CLI for the Web42 Agent Marketplace - push, install, and remix OpenClaw agent packages.
3
+ CLI for the Web42 Agent Network authenticate, publish, discover, and interact with A2A agents.
4
4
 
5
5
  ## Installation
6
6
 
7
- To install the CLI globally, run:
8
-
9
- ```
7
+ ```bash
10
8
  npm install -g @web42/cli
11
9
  ```
12
10
 
13
11
  ## Authentication
14
12
 
15
- Authenticate with the marketplace by running:
13
+ ```bash
14
+ web42 auth login # Sign in via GitHub OAuth
15
+ web42 auth logout # Sign out
16
+ web42 auth whoami # Show current user
17
+ ```
18
+
19
+ ## Commands
16
20
 
21
+ ### `web42 search <query>`
22
+
23
+ Search the network for agents.
24
+
25
+ ```bash
26
+ web42 search "data analysis"
27
+ web42 search "image processing" --limit 20
17
28
  ```
18
- web42 login
29
+
30
+ | Option | Description |
31
+ |---|---|
32
+ | `-l, --limit <number>` | Max results to show (default: 10) |
33
+
34
+ ---
35
+
36
+ ### `web42 send <agent> <message>`
37
+
38
+ Send a message to an A2A agent. `<agent>` can be a slug (`@user/agent`) or a direct URL (`http://localhost:3001`).
39
+
40
+ ```bash
41
+ web42 send @alice/summarizer "Summarize this document"
42
+ web42 send http://localhost:3001 "Hello"
19
43
  ```
20
44
 
21
- ## Supported Platforms
45
+ | Option | Description |
46
+ |---|---|
47
+ | `--new` | Start a new conversation (clears saved context) |
48
+ | `--context <id>` | Use a specific context ID |
49
+ | `--task-id <id>` | Reply to a specific task (e.g. one in `input-required` state) |
22
50
 
23
- | Platform | Status |
24
- |-----------|--------------|
25
- | openclaw | Fully Supported |
26
- | claude | Fully Supported |
51
+ ---
27
52
 
28
- ## CLI Commands Reference
53
+ ### `web42 serve`
29
54
 
30
- ### General Commands
55
+ Start a local A2A server for your agent, bridging to an OpenClaw gateway.
31
56
 
32
- | Command | Description |
33
- |--------------|-----------------------------------------|
34
- | `web42 install <agent>` | Install an agent package from the marketplace |
35
- | `web42 push` | Push your agent package to the marketplace |
36
- | `web42 pull` | Pull the latest agent state from the marketplace |
37
- | `web42 list` | List installed agents |
38
- | `web42 update <agent>` | Update an installed agent to the latest version |
39
- | `web42 uninstall <agent>` | Uninstall an agent |
40
- | `web42 search <query>` | Search the marketplace for agents |
41
- | `web42 remix <agent>` | Remix an agent package to your account |
42
- | `web42 sync` | Check sync status between local workspace and the marketplace |
57
+ ```bash
58
+ web42 serve
59
+ web42 serve --port 3001 --url https://my-agent.ngrok.io --verbose
60
+ ```
43
61
 
44
- ### Claude-Specific Examples
62
+ | Option | Description |
63
+ |---|---|
64
+ | `--port <port>` | Port to listen on (default: 4000) |
65
+ | `--url <url>` | Public URL for registration and AgentCard (e.g. from ngrok) |
66
+ | `--openclaw-port <port>` | OpenClaw gateway port (default: 18789) |
67
+ | `--openclaw-token <token>` | OpenClaw gateway auth token (or `OPENCLAW_GATEWAY_TOKEN`) |
68
+ | `--openclaw-agent <id>` | OpenClaw agent ID to target (default: `main`) |
69
+ | `--client-id <id>` | Developer app client ID (or `W42_CLIENT_ID`) |
70
+ | `--client-secret <secret>` | Developer app client secret (or `W42_CLIENT_SECRET`) |
71
+ | `--visibility <vis>` | Marketplace visibility: `public` or `private` |
72
+ | `--verbose` | Enable verbose request/response logging |
45
73
 
46
- - **Initialize a Project:**
47
- ```
48
- web42 init
49
- ```
74
+ ---
50
75
 
51
- - **Pack an Agent:**
52
- ```
53
- web42 pack --agent <name>
54
- ```
76
+ ### `web42 register <url>`
55
77
 
56
- - **Push an Agent:**
57
- ```
58
- web42 push --agent <name>
59
- ```
78
+ Register an agent with the Web42 Network. The URL must serve `/.well-known/agent-card.json`.
60
79
 
61
- - **Install an Agent Globally:**
62
- ```
63
- web42 claude install @user/agent
64
- ```
80
+ ```bash
81
+ web42 register https://my-agent.example.com
82
+ web42 register https://my-agent.example.com --visibility private --tags "nlp,summarization"
83
+ ```
84
+
85
+ | Option | Description |
86
+ |---|---|
87
+ | `--price <cents>` | Price in cents (default: 0 = free) |
88
+ | `--license <license>` | License (e.g. `MIT`, `Apache-2.0`) |
89
+ | `--visibility <vis>` | `public` or `private` (default: `public`) |
90
+ | `--tags <tags>` | Comma-separated tags |
91
+ | `--categories <cats>` | Comma-separated categories |
65
92
 
66
- - **Install an Agent Locally:**
67
- ```
68
- web42 claude install -g @user/agent
69
- ```
93
+ ---
70
94
 
71
- ## Versioning
95
+ ## Environment variables
72
96
 
73
- Version `0.2.0` introduces Claude Code support.
97
+ ```bash
98
+ W42_CLIENT_ID=your-client-id
99
+ W42_CLIENT_SECRET=your-client-secret
100
+ OPENCLAW_GATEWAY_TOKEN=your-openclaw-token
101
+ ```
@@ -1,18 +1,41 @@
1
- import { Command } from "commander";
1
+ import { ClientFactory, ClientFactoryOptions, JsonRpcTransportFactory, } from "@a2a-js/sdk/client";
2
2
  import chalk from "chalk";
3
+ import { Command } from "commander";
3
4
  import ora from "ora";
4
5
  import { v4 as uuidv4 } from "uuid";
5
- import { requireAuth, setConfigValue, getConfigValue } from "../utils/config.js";
6
6
  import { apiPost } from "../utils/api.js";
7
+ import { getConfigValue, requireAuth, setConfigValue } from "../utils/config.js";
7
8
  function isUrl(s) {
8
9
  return s.startsWith("http://") || s.startsWith("https://");
9
10
  }
11
+ function printPart(part) {
12
+ if (part.kind === "text") {
13
+ if (part.text)
14
+ process.stdout.write(part.text);
15
+ }
16
+ else if (part.kind === "file") {
17
+ const f = part.file;
18
+ const label = [f.name, f.mimeType].filter(Boolean).join(" ");
19
+ process.stdout.write(`\n[file${label ? `: ${label}` : ""}]\n`);
20
+ if ("uri" in f) {
21
+ process.stdout.write(f.uri + "\n");
22
+ }
23
+ else {
24
+ process.stdout.write(`<${f.bytes.length} base64 chars>\n`);
25
+ }
26
+ }
27
+ else if (part.kind === "data") {
28
+ process.stdout.write("\n" + JSON.stringify(part.data, null, 2) + "\n");
29
+ }
30
+ }
10
31
  function getCachedToken(slug) {
11
32
  const raw = getConfigValue(`agentTokens.${slug}`);
12
33
  if (!raw)
13
34
  return null;
14
35
  try {
15
- const cached = typeof raw === "string" ? JSON.parse(raw) : raw;
36
+ const cached = typeof raw === "string"
37
+ ? JSON.parse(raw)
38
+ : raw;
16
39
  if (new Date(cached.expiresAt) <= new Date())
17
40
  return null;
18
41
  return cached;
@@ -27,6 +50,7 @@ export const sendCommand = new Command("send")
27
50
  .argument("<message>", "Message to send")
28
51
  .option("--new", "Start a new conversation (clears saved context)")
29
52
  .option("--context <id>", "Use a specific context ID")
53
+ .option("--task-id <id>", "Reply to a specific task (e.g. one in input-required state)")
30
54
  .action(async (rawAgent, userMessage, opts) => {
31
55
  // Normalize slug: @user/name → @user~name (DB format)
32
56
  const agent = rawAgent.includes("/") && !isUrl(rawAgent)
@@ -37,10 +61,30 @@ export const sendCommand = new Command("send")
37
61
  let bearerToken;
38
62
  let agentKey;
39
63
  if (isUrl(agent)) {
40
- // Direct URL mode — local development, no handshake needed
41
64
  agentUrl = agent;
42
- bearerToken = config.token;
43
65
  agentKey = new URL(agent).host.replace(/[.:]/g, "-");
66
+ const cached = getCachedToken(agentKey);
67
+ if (cached) {
68
+ bearerToken = cached.token;
69
+ }
70
+ else {
71
+ const spinner = ora("Getting auth token...").start();
72
+ try {
73
+ const res = await apiPost("/api/auth/token", {});
74
+ bearerToken = res.token;
75
+ setConfigValue(`agentTokens.${agentKey}`, JSON.stringify({
76
+ token: res.token,
77
+ agentUrl,
78
+ expiresAt: res.expiresAt,
79
+ }));
80
+ spinner.stop();
81
+ }
82
+ catch (err) {
83
+ spinner.fail("Failed to get auth token");
84
+ console.error(chalk.red(String(err)));
85
+ process.exit(1);
86
+ }
87
+ }
44
88
  }
45
89
  else {
46
90
  // Slug mode — handshake with Web42 Network platform
@@ -85,20 +129,6 @@ export const sendCommand = new Command("send")
85
129
  contextId = getConfigValue(contextKey) ?? uuidv4();
86
130
  }
87
131
  setConfigValue(contextKey, contextId);
88
- // Dynamically import @a2a-js/sdk client
89
- let ClientFactory;
90
- let JsonRpcTransportFactory;
91
- let ClientFactoryOptions;
92
- try {
93
- const clientModule = await import("@a2a-js/sdk/client");
94
- ClientFactory = clientModule.ClientFactory;
95
- JsonRpcTransportFactory = clientModule.JsonRpcTransportFactory;
96
- ClientFactoryOptions = clientModule.ClientFactoryOptions;
97
- }
98
- catch {
99
- console.error(chalk.red("Failed to load @a2a-js/sdk. Run: pnpm add @a2a-js/sdk"));
100
- process.exit(1);
101
- }
102
132
  const bearerInterceptor = {
103
133
  before: async (args) => {
104
134
  if (!args.options)
@@ -119,8 +149,7 @@ export const sendCommand = new Command("send")
119
149
  interceptors: [bearerInterceptor],
120
150
  },
121
151
  }));
122
- const a2aBaseUrl = new URL(agentUrl).origin;
123
- client = await factory.createFromUrl(a2aBaseUrl);
152
+ client = await factory.createFromUrl(agentUrl);
124
153
  connectSpinner.stop();
125
154
  }
126
155
  catch {
@@ -136,22 +165,67 @@ export const sendCommand = new Command("send")
136
165
  parts: [{ kind: "text", text: userMessage }],
137
166
  kind: "message",
138
167
  contextId,
168
+ ...(opts.taskId ? { taskId: opts.taskId } : {}),
139
169
  },
140
170
  });
141
171
  for await (const event of stream) {
142
- if (event.kind === "artifact-update") {
143
- const artifact = event.artifact;
144
- const text = (artifact.parts ?? [])
145
- .filter((p) => p.kind === "text")
146
- .map((p) => p.text ?? "")
147
- .join("");
148
- if (text)
149
- process.stdout.write(text);
172
+ if (event.kind === "message" && event.role === "agent") {
173
+ for (const part of event.parts)
174
+ printPart(part);
175
+ }
176
+ else if (event.kind === "artifact-update") {
177
+ // When append is true we're receiving streaming chunks — write inline.
178
+ // When it's a new artifact (append falsy), separate from prior output.
179
+ if (!event.append)
180
+ process.stdout.write("\n");
181
+ for (const part of event.artifact.parts ?? [])
182
+ printPart(part);
150
183
  }
151
- if (event.kind === "status-update") {
152
- const update = event;
153
- if (update.status?.state === "failed") {
154
- console.error(chalk.red("\nAgent returned an error."));
184
+ else if (event.kind === "status-update") {
185
+ if (event.status?.message) {
186
+ for (const part of event.status.message.parts ?? [])
187
+ printPart(part);
188
+ }
189
+ const state = event.status?.state;
190
+ if (state === "input-required") {
191
+ process.stdout.write("\n");
192
+ console.log(chalk.yellow(`[task ${event.taskId} is awaiting input — reply with --task-id ${event.taskId}]`));
193
+ }
194
+ else if (state === "auth-required") {
195
+ console.error(chalk.red("\nAgent requires authentication."));
196
+ process.exit(1);
197
+ }
198
+ else if (state === "failed" ||
199
+ state === "canceled" ||
200
+ state === "rejected") {
201
+ console.error(chalk.red(`\nAgent ${state}.`));
202
+ process.exit(1);
203
+ }
204
+ }
205
+ else if (event.kind === "task") {
206
+ // Non-streaming fallback: server returned the full task object.
207
+ // Print accumulated artifacts and handle terminal state.
208
+ const task = event;
209
+ for (const artifact of task.artifacts ?? []) {
210
+ process.stdout.write("\n");
211
+ for (const part of artifact.parts ?? [])
212
+ printPart(part);
213
+ }
214
+ if (task.status?.message) {
215
+ for (const part of task.status.message.parts ?? [])
216
+ printPart(part);
217
+ }
218
+ const taskState = task.status?.state;
219
+ if (taskState === "input-required") {
220
+ process.stdout.write("\n");
221
+ console.log(chalk.yellow(`[task ${task.id} is awaiting input — reply with --task-id ${task.id}]`));
222
+ }
223
+ else if (taskState === "auth-required") {
224
+ console.error(chalk.red("\nAgent requires authentication."));
225
+ process.exit(1);
226
+ }
227
+ else if (taskState === "failed" || taskState === "canceled" || taskState === "rejected") {
228
+ console.error(chalk.red(`\nAgent ${taskState}.`));
155
229
  process.exit(1);
156
230
  }
157
231
  }