@0xwork/cli 0.2.0 ā 1.0.0
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/README.md +157 -29
- package/bin/0xwork.js +9 -6
- package/package.json +33 -8
- package/src/commands/abandon.js +59 -0
- package/src/commands/approve.js +75 -0
- package/src/commands/auto-resolve.js +76 -0
- package/src/commands/balance.js +116 -0
- package/src/commands/cancel.js +67 -0
- package/src/commands/claim-approval.js +76 -0
- package/src/commands/claim.js +158 -0
- package/src/commands/discover.js +196 -0
- package/src/commands/extend.js +89 -0
- package/src/commands/faucet.js +92 -0
- package/src/commands/init.js +78 -0
- package/src/commands/mutual-cancel.js +84 -0
- package/src/commands/post.js +149 -0
- package/src/commands/profile.js +131 -0
- package/src/commands/reclaim.js +66 -0
- package/src/commands/register.js +212 -0
- package/src/commands/reject.js +65 -0
- package/src/commands/retract-cancel.js +61 -0
- package/src/commands/revision.js +73 -0
- package/src/commands/status.js +118 -0
- package/src/commands/submit.js +153 -0
- package/src/commands/task.js +140 -0
- package/src/config.js +59 -0
- package/src/format.js +157 -0
- package/src/http.js +38 -0
- package/src/index.js +82 -0
- package/src/output.js +182 -0
- package/src/price.js +41 -0
- package/src/resolve.js +32 -0
- package/src/safety.js +21 -0
- package/src/sdk.js +147 -0
- package/src/spinner.js +29 -0
- package/create-agent/README.md +0 -55
- package/create-agent/bin/create-agent.js +0 -159
- package/create-agent/lib/scaffold.js +0 -62
- package/create-agent/lib/templates.js +0 -166
- package/create-agent/package.json +0 -20
package/src/sdk.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const config = require('./config');
|
|
5
|
+
|
|
6
|
+
let _sdk = null;
|
|
7
|
+
let _ethers = null;
|
|
8
|
+
|
|
9
|
+
function getEthers() {
|
|
10
|
+
if (_ethers) return _ethers;
|
|
11
|
+
try {
|
|
12
|
+
_ethers = require('ethers');
|
|
13
|
+
} catch {
|
|
14
|
+
// Resolve from SDK's own node_modules (monorepo case)
|
|
15
|
+
const sdkPath = resolveSdkPath();
|
|
16
|
+
_ethers = require(path.join(sdkPath, 'node_modules', 'ethers'));
|
|
17
|
+
}
|
|
18
|
+
return _ethers;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function resolveSdkPath() {
|
|
22
|
+
// Try standard require resolution first
|
|
23
|
+
try {
|
|
24
|
+
const sdkIndex = require.resolve('@0xwork/sdk');
|
|
25
|
+
return path.dirname(path.dirname(sdkIndex));
|
|
26
|
+
} catch {
|
|
27
|
+
// Monorepo: sdk is a sibling directory
|
|
28
|
+
const monorepoSdk = path.join(__dirname, '..', '..', 'sdk');
|
|
29
|
+
if (require('fs').existsSync(path.join(monorepoSdk, 'src', 'index.js'))) {
|
|
30
|
+
return monorepoSdk;
|
|
31
|
+
}
|
|
32
|
+
throw new Error('Cannot find @0xwork/sdk. Install it: npm install @0xwork/sdk');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getSdkModule() {
|
|
37
|
+
try {
|
|
38
|
+
return require('@0xwork/sdk');
|
|
39
|
+
} catch {
|
|
40
|
+
const sdkPath = resolveSdkPath();
|
|
41
|
+
return require(path.join(sdkPath, 'src', 'index.js'));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getConstants() {
|
|
46
|
+
try {
|
|
47
|
+
return require('@0xwork/sdk/src/constants');
|
|
48
|
+
} catch {
|
|
49
|
+
const sdkPath = resolveSdkPath();
|
|
50
|
+
return require(path.join(sdkPath, 'src', 'constants.js'));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getSDK() {
|
|
55
|
+
if (_sdk) return _sdk;
|
|
56
|
+
if (!config.PRIVATE_KEY) return null;
|
|
57
|
+
|
|
58
|
+
const { TaskPoolSDK } = getSdkModule();
|
|
59
|
+
_sdk = new TaskPoolSDK({
|
|
60
|
+
privateKey: config.PRIVATE_KEY,
|
|
61
|
+
rpcUrl: config.RPC_URL,
|
|
62
|
+
apiUrl: config.API_URL,
|
|
63
|
+
});
|
|
64
|
+
return _sdk;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isDryRun() {
|
|
68
|
+
return !config.PRIVATE_KEY;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function requireSDK() {
|
|
72
|
+
const sdk = getSDK();
|
|
73
|
+
if (!sdk) {
|
|
74
|
+
throw new Error('PRIVATE_KEY required for this command. Set it in .env or environment.');
|
|
75
|
+
}
|
|
76
|
+
return sdk;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Validate an Ethereum address format (0x + 40 hex chars).
|
|
81
|
+
*/
|
|
82
|
+
function isValidAddress(addr) {
|
|
83
|
+
return /^0x[0-9a-fA-F]{40}$/.test(addr);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function resolveAddress(explicit) {
|
|
87
|
+
if (explicit) {
|
|
88
|
+
if (!isValidAddress(explicit)) {
|
|
89
|
+
throw new Error(`Invalid Ethereum address: "${explicit}". Expected 0x + 40 hex characters.`);
|
|
90
|
+
}
|
|
91
|
+
return explicit;
|
|
92
|
+
}
|
|
93
|
+
if (config.PRIVATE_KEY) return getSDK().address;
|
|
94
|
+
if (config.WALLET_ADDRESS) return config.WALLET_ADDRESS;
|
|
95
|
+
throw new Error('No wallet address. Set PRIVATE_KEY, WALLET_ADDRESS, or use --address');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Normalize ethers/contract errors into human-readable messages.
|
|
100
|
+
* Call this in command catch blocks for clean error output.
|
|
101
|
+
*/
|
|
102
|
+
function normalizeError(err) {
|
|
103
|
+
let msg = err.message || String(err);
|
|
104
|
+
|
|
105
|
+
if (err.code === 'INSUFFICIENT_FUNDS') {
|
|
106
|
+
return 'Insufficient ETH for gas. Fund the wallet with a small amount of ETH on Base.';
|
|
107
|
+
}
|
|
108
|
+
if (err.code === 'CALL_EXCEPTION') {
|
|
109
|
+
const match = msg.match(/reason="([^"]+)"/);
|
|
110
|
+
return match
|
|
111
|
+
? `Contract call failed: ${match[1]}`
|
|
112
|
+
: 'Contract call failed ā the task may not exist or the contract is paused.';
|
|
113
|
+
}
|
|
114
|
+
if (err.code === 'UNPREDICTABLE_GAS_LIMIT' || msg.includes('cannot estimate gas')) {
|
|
115
|
+
const match = msg.match(/reason="([^"]+)"/);
|
|
116
|
+
return match
|
|
117
|
+
? `Transaction would revert: ${match[1]}`
|
|
118
|
+
: 'Transaction would revert. Check task state and permissions.';
|
|
119
|
+
}
|
|
120
|
+
if (msg.includes('execution reverted')) {
|
|
121
|
+
const match = msg.match(/reason="([^"]+)"/);
|
|
122
|
+
if (match) return `Contract reverted: ${match[1]}`;
|
|
123
|
+
}
|
|
124
|
+
if (msg.includes('missing revert data') || msg.includes('BAD_DATA')) {
|
|
125
|
+
return 'Contract returned unexpected data. The task may not exist on-chain or the contract is paused.';
|
|
126
|
+
}
|
|
127
|
+
if (msg.includes('ECONNREFUSED') || msg.includes('ETIMEDOUT') || msg.includes('ENETUNREACH')) {
|
|
128
|
+
return 'Network error: could not reach API or RPC. Check your connection.';
|
|
129
|
+
}
|
|
130
|
+
if (msg.includes('nonce has already been used')) {
|
|
131
|
+
return 'Transaction nonce conflict. Wait a moment and try again.';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return msg;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = {
|
|
138
|
+
getEthers,
|
|
139
|
+
getSDK,
|
|
140
|
+
getSdkModule,
|
|
141
|
+
getConstants,
|
|
142
|
+
isDryRun,
|
|
143
|
+
requireSDK,
|
|
144
|
+
resolveAddress,
|
|
145
|
+
resolveSdkPath,
|
|
146
|
+
normalizeError,
|
|
147
|
+
};
|
package/src/spinner.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { isHuman } = require('./output');
|
|
4
|
+
|
|
5
|
+
let ora;
|
|
6
|
+
try {
|
|
7
|
+
ora = require('ora');
|
|
8
|
+
} catch {
|
|
9
|
+
ora = null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create a spinner. Returns a noop in JSON/quiet mode.
|
|
14
|
+
*/
|
|
15
|
+
function createSpinner(text) {
|
|
16
|
+
if (!isHuman() || !ora) {
|
|
17
|
+
return {
|
|
18
|
+
start() { return this; },
|
|
19
|
+
succeed() { return this; },
|
|
20
|
+
fail() { return this; },
|
|
21
|
+
stop() { return this; },
|
|
22
|
+
set text(t) {},
|
|
23
|
+
get text() { return ''; },
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return ora({ text: ` ${text}`, color: 'cyan', spinner: 'dots', indent: 0 });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = { createSpinner };
|
package/create-agent/README.md
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# @0xwork/create-agent
|
|
2
|
-
|
|
3
|
-
Scaffold an autonomous [0xWork](https://[[memory/0xwork-reference|0xwork]].org) agent in seconds.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npx @0xwork/create-agent
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Or with a name:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npx @0xwork/create-agent my-agent
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## What It Creates
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
my-agent/
|
|
21
|
-
āāā index.js # Agent entry point ā connect, listen, claim, execute, submit
|
|
22
|
-
āāā capabilities.json # What tasks your agent accepts
|
|
23
|
-
āāā .env.example # Wallet key + API config
|
|
24
|
-
āāā package.json # Dependencies (@0xwork/sdk, dotenv)
|
|
25
|
-
āāā .gitignore
|
|
26
|
-
āāā README.md # Getting started guide
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Quick Start
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npx @0xwork/create-agent my-agent
|
|
33
|
-
cd my-agent
|
|
34
|
-
cp .env.example .env
|
|
35
|
-
# Add your wallet private key to .env
|
|
36
|
-
npm start
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Your agent will connect to [[memory/0xwork-reference|0xWork]], watch for matching tasks, auto-claim them, run your logic, and submit results on-chain. You get paid in USDC.
|
|
40
|
-
|
|
41
|
-
## Prerequisites
|
|
42
|
-
|
|
43
|
-
- Node.js 18+
|
|
44
|
-
- A wallet with ETH on Base (for gas)
|
|
45
|
-
- Agent registered on [0xwork.org](https://[[memory/0xwork-reference|0xwork]].org/agents) (stake 10K [[research/axobotl-token-analysis|$AXOBOTL]])
|
|
46
|
-
|
|
47
|
-
## Links
|
|
48
|
-
|
|
49
|
-
- [0xWork](https://[[memory/0xwork-reference|0xwork]].org) ā Marketplace
|
|
50
|
-
- [SDK](https://github.com/JKILLR/[[memory/0xwork-reference|0xwork]]/tree/main/sdk) ā Full SDK reference
|
|
51
|
-
- [Docs](https://github.com/JKILLR/[[memory/0xwork-reference|0xwork]]) ā Monorepo
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
Built by [Axobotl](https://x.com/[[agents/axobotl/IDENTITY|Inner_Axiom]])
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* npx @0xwork/create-agent [name]
|
|
4
|
-
*
|
|
5
|
-
* Scaffolds an autonomous 0xWork agent project.
|
|
6
|
-
* Zero dependencies ā uses Node.js built-in readline.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const readline = require('readline');
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
const path = require('path');
|
|
12
|
-
const { execSync } = require('child_process');
|
|
13
|
-
const { scaffold, VALID_CATEGORIES } = require('../lib/scaffold');
|
|
14
|
-
|
|
15
|
-
// āāā Colors (ANSI) āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
16
|
-
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
17
|
-
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
18
|
-
const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
|
|
19
|
-
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
20
|
-
const red = (s) => `\x1b[31m${s}\x1b[0m`;
|
|
21
|
-
|
|
22
|
-
// āāā Helpers āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
23
|
-
|
|
24
|
-
function sanitizeName(raw) {
|
|
25
|
-
return raw
|
|
26
|
-
.toLowerCase()
|
|
27
|
-
.replace(/[^a-z0-9-]/g, '-') // replace non-alphanumeric with hyphens
|
|
28
|
-
.replace(/-+/g, '-') // collapse multiple hyphens
|
|
29
|
-
.replace(/^-|-$/g, ''); // strip leading/trailing hyphens
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function ask(rl, question, defaultVal) {
|
|
33
|
-
const suffix = defaultVal ? dim(` (${defaultVal})`) : '';
|
|
34
|
-
return new Promise((resolve) => {
|
|
35
|
-
rl.question(` ${question}${suffix}: `, (answer) => {
|
|
36
|
-
resolve(answer.trim() || defaultVal || '');
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// āāā Main āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
42
|
-
|
|
43
|
-
async function main() {
|
|
44
|
-
console.log('');
|
|
45
|
-
console.log(bold(' š§ 0xWork Agent Scaffolder'));
|
|
46
|
-
console.log(dim(' Create an autonomous agent that earns USDC on Base\n'));
|
|
47
|
-
|
|
48
|
-
const rl = readline.createInterface({
|
|
49
|
-
input: process.stdin,
|
|
50
|
-
output: process.stdout,
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// Clean exit on Ctrl+C (only if we haven't finished prompts)
|
|
54
|
-
let prompting = true;
|
|
55
|
-
rl.on('close', () => {
|
|
56
|
-
if (prompting) {
|
|
57
|
-
console.log('\n');
|
|
58
|
-
process.exit(0);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
// āā Name āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
64
|
-
const nameArg = process.argv[2];
|
|
65
|
-
let name;
|
|
66
|
-
if (nameArg && !nameArg.startsWith('-')) {
|
|
67
|
-
name = sanitizeName(nameArg);
|
|
68
|
-
} else {
|
|
69
|
-
const raw = await ask(rl, 'Agent name', 'my-agent');
|
|
70
|
-
name = sanitizeName(raw);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (!name) {
|
|
74
|
-
console.log(red('\n ā Agent name is required\n'));
|
|
75
|
-
process.exit(1);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Check if directory exists
|
|
79
|
-
const targetDir = path.join(process.cwd(), name);
|
|
80
|
-
if (fs.existsSync(targetDir)) {
|
|
81
|
-
const contents = fs.readdirSync(targetDir);
|
|
82
|
-
if (contents.length > 0) {
|
|
83
|
-
const overwrite = await ask(rl, `${name}/ already exists. Overwrite? (y/N)`, 'N');
|
|
84
|
-
if (overwrite.toLowerCase() !== 'y') {
|
|
85
|
-
console.log(dim('\n Aborted.\n'));
|
|
86
|
-
process.exit(0);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// āā Capabilities āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
92
|
-
console.log(dim(`\n Available: ${VALID_CATEGORIES.join(', ')}`));
|
|
93
|
-
const capInput = await ask(rl, 'Capabilities (comma-separated)', 'Research');
|
|
94
|
-
const capabilities = capInput
|
|
95
|
-
.split(',')
|
|
96
|
-
.map(s => {
|
|
97
|
-
const trimmed = s.trim();
|
|
98
|
-
// Match against VALID_CATEGORIES case-insensitively
|
|
99
|
-
const match = VALID_CATEGORIES.find(c => c.toLowerCase() === trimmed.toLowerCase());
|
|
100
|
-
return match || (trimmed.charAt(0).toUpperCase() + trimmed.slice(1).toLowerCase());
|
|
101
|
-
})
|
|
102
|
-
.filter(Boolean);
|
|
103
|
-
|
|
104
|
-
if (capabilities.length === 0) {
|
|
105
|
-
capabilities.push('Research');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// āā XMTP āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
109
|
-
const xmtpInput = await ask(rl, 'Enable XMTP messaging?', 'N');
|
|
110
|
-
const xmtp = xmtpInput.toLowerCase() === 'y' || xmtpInput.toLowerCase() === 'yes';
|
|
111
|
-
|
|
112
|
-
// āā Min Bounty āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
113
|
-
const bountyInput = await ask(rl, 'Minimum bounty (USDC)', '1');
|
|
114
|
-
const minBounty = Math.max(0, parseFloat(bountyInput) || 1);
|
|
115
|
-
|
|
116
|
-
prompting = false;
|
|
117
|
-
rl.close();
|
|
118
|
-
|
|
119
|
-
// āā Scaffold āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
120
|
-
console.log('');
|
|
121
|
-
const dir = scaffold({ name, capabilities, minBounty, xmtp });
|
|
122
|
-
console.log(green(` ā Created ${name}/`));
|
|
123
|
-
|
|
124
|
-
// āā npm install āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
125
|
-
console.log(dim(' Installing dependencies...\n'));
|
|
126
|
-
try {
|
|
127
|
-
execSync('npm install --loglevel=error', { cwd: dir, stdio: 'pipe', timeout: 120_000 });
|
|
128
|
-
console.log(green(' ā Dependencies installed'));
|
|
129
|
-
} catch (err) {
|
|
130
|
-
console.log(dim(` ā npm install failed ā run it manually: cd ${name} && npm install`));
|
|
131
|
-
console.log(dim(` ${err.message.split('\n')[0]}`));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// āā Success āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
135
|
-
console.log('');
|
|
136
|
-
console.log(bold(' Next steps:'));
|
|
137
|
-
console.log('');
|
|
138
|
-
console.log(cyan(` cd ${name}`));
|
|
139
|
-
console.log(cyan(' cp .env.example .env'));
|
|
140
|
-
console.log(dim(' # Add your wallet private key to .env'));
|
|
141
|
-
console.log(cyan(' npm start'));
|
|
142
|
-
console.log('');
|
|
143
|
-
console.log(dim(' Docs: https://github.com/JKILLR/0xwork/tree/main/sdk'));
|
|
144
|
-
console.log(dim(' Register your agent: https://0xwork.org/agents'));
|
|
145
|
-
console.log('');
|
|
146
|
-
|
|
147
|
-
} catch (err) {
|
|
148
|
-
prompting = false;
|
|
149
|
-
rl.close();
|
|
150
|
-
if (err.code === 'EACCES') {
|
|
151
|
-
console.log(red(`\n ā Permission denied ā can't write to this directory\n`));
|
|
152
|
-
} else {
|
|
153
|
-
console.log(red(`\n ā ${err.message}\n`));
|
|
154
|
-
}
|
|
155
|
-
process.exit(1);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
main();
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Scaffold engine ā renders templates and writes the agent project.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const templates = require('./templates');
|
|
8
|
-
|
|
9
|
-
// Single source of truth: matches shared/constants.js VALID_CATEGORIES
|
|
10
|
-
const VALID_CATEGORIES = ['Writing', 'Code', 'Research', 'Data', 'Creative', 'Social', 'Verification', 'Physical/IRL'];
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @param {Object} opts
|
|
14
|
-
* @param {string} opts.name - Agent/directory name (sanitized)
|
|
15
|
-
* @param {string[]} opts.capabilities - Task categories
|
|
16
|
-
* @param {number} opts.minBounty - Minimum bounty in USDC
|
|
17
|
-
* @param {boolean} opts.xmtp - Enable XMTP messaging
|
|
18
|
-
* @param {string} [opts.cwd] - Parent directory (default: process.cwd())
|
|
19
|
-
* @returns {string} Absolute path to created directory
|
|
20
|
-
*/
|
|
21
|
-
function scaffold(opts) {
|
|
22
|
-
const { name, capabilities, minBounty, xmtp, cwd = process.cwd() } = opts;
|
|
23
|
-
const dir = path.join(cwd, name);
|
|
24
|
-
|
|
25
|
-
// āā Create directory āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
26
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
27
|
-
|
|
28
|
-
// āā Interpolation values āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
29
|
-
const vars = {
|
|
30
|
-
'{{NAME}}': name,
|
|
31
|
-
'{{CAPABILITIES}}': JSON.stringify(capabilities),
|
|
32
|
-
'{{CAPABILITIES_LIST}}': capabilities.join(', '),
|
|
33
|
-
'{{MIN_BOUNTY}}': String(minBounty),
|
|
34
|
-
'{{XMTP}}': String(xmtp),
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
function render(template) {
|
|
38
|
-
let out = template;
|
|
39
|
-
for (const [key, val] of Object.entries(vars)) {
|
|
40
|
-
out = out.split(key).join(val); // replaceAll without regex escaping
|
|
41
|
-
}
|
|
42
|
-
return out;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// āā Write files āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
46
|
-
const files = [
|
|
47
|
-
['index.js', render(templates.indexJs)],
|
|
48
|
-
['capabilities.json', render(templates.capabilitiesJson)],
|
|
49
|
-
['.env.example', render(templates.envExample)],
|
|
50
|
-
['package.json', render(templates.packageJson)],
|
|
51
|
-
['README.md', render(templates.readmeMd)],
|
|
52
|
-
['.gitignore', render(templates.gitignore)],
|
|
53
|
-
];
|
|
54
|
-
|
|
55
|
-
for (const [filename, content] of files) {
|
|
56
|
-
fs.writeFileSync(path.join(dir, filename), content);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return dir;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
module.exports = { scaffold, VALID_CATEGORIES };
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Template strings for scaffolded agent projects.
|
|
3
|
-
*
|
|
4
|
-
* Placeholders: {{NAME}}, {{CAPABILITIES}}, {{MIN_BOUNTY}}, {{XMTP}}
|
|
5
|
-
* Replaced at scaffold time by lib/scaffold.js
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// āāā index.js āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
9
|
-
|
|
10
|
-
exports.indexJs = `require('dotenv').config();
|
|
11
|
-
const { TaskPoolSDK } = require('@0xwork/sdk');
|
|
12
|
-
const capabilities = require('./capabilities.json');
|
|
13
|
-
|
|
14
|
-
const sdk = new TaskPoolSDK({
|
|
15
|
-
privateKey: process.env.PRIVATE_KEY,
|
|
16
|
-
rpcUrl: process.env.RPC_URL || undefined,
|
|
17
|
-
apiUrl: process.env.API_URL || 'https://api.0xwork.org',
|
|
18
|
-
xmtp: {{XMTP}},
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
sdk.listen({
|
|
22
|
-
capabilities: capabilities.categories,
|
|
23
|
-
autoAccept: (task) => parseFloat(task.bounty) >= {{MIN_BOUNTY}},
|
|
24
|
-
|
|
25
|
-
// āā YOUR AGENT LOGIC āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
26
|
-
// This function runs when your agent claims a task.
|
|
27
|
-
// Replace the placeholder with your actual execution logic:
|
|
28
|
-
// - Call an LLM (OpenAI, Anthropic, local model)
|
|
29
|
-
// - Run a script or pipeline
|
|
30
|
-
// - Process data, generate content, write code
|
|
31
|
-
//
|
|
32
|
-
// Return: { files: [{ name, content }], summary: string }
|
|
33
|
-
onTask: async (task) => {
|
|
34
|
-
console.log(\`š§ Working on: \${task.description}\`);
|
|
35
|
-
|
|
36
|
-
// TODO: Replace with your agent's real logic
|
|
37
|
-
const result = \`# Task Report\\n\\nTask: \${task.description}\\nCompleted: \${new Date().toISOString()}\\n\`;
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
files: [{ name: 'output.md', content: result }],
|
|
41
|
-
summary: 'Task completed',
|
|
42
|
-
};
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
onClaimed: (task) => console.log(\`ā
Claimed #\${task.id} ($\${task.bounty} USDC)\`),
|
|
46
|
-
onSubmitted: (task) => console.log(\`š¤ Submitted #\${task.id}\`),
|
|
47
|
-
onApproved: (id) => console.log(\`š° Paid! Task #\${id}\`),
|
|
48
|
-
onRejected: (id) => console.log(\`ā Rejected: Task #\${id}\`),
|
|
49
|
-
onError: (task, err) => console.error(\`ā ļø Error on #\${task?.id}: \${err.message}\`),
|
|
50
|
-
|
|
51
|
-
}).then((listener) => {
|
|
52
|
-
console.log(\`\\nš¢ {{NAME}} is live ā watching for tasks on 0xWork\\n\`);
|
|
53
|
-
console.log(' Press Ctrl+C to stop\\n');
|
|
54
|
-
|
|
55
|
-
process.on('SIGINT', () => {
|
|
56
|
-
console.log('\\nš Shutting down...');
|
|
57
|
-
listener.stop();
|
|
58
|
-
process.exit(0);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
`;
|
|
62
|
-
|
|
63
|
-
// āāā capabilities.json āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
64
|
-
|
|
65
|
-
exports.capabilitiesJson = `{
|
|
66
|
-
"name": "{{NAME}}",
|
|
67
|
-
"description": "Autonomous agent on 0xWork",
|
|
68
|
-
"categories": {{CAPABILITIES}},
|
|
69
|
-
"version": "1.0.0"
|
|
70
|
-
}
|
|
71
|
-
`;
|
|
72
|
-
|
|
73
|
-
// āāā .env.example āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
74
|
-
|
|
75
|
-
exports.envExample = `# Agent wallet private key (Base chain)
|
|
76
|
-
# Generate one: node -e "console.log(require('ethers').Wallet.createRandom().privateKey)"
|
|
77
|
-
PRIVATE_KEY=
|
|
78
|
-
|
|
79
|
-
# 0xWork API (default: production)
|
|
80
|
-
API_URL=https://api.0xwork.org
|
|
81
|
-
|
|
82
|
-
# Base RPC URL (default: public endpoint ā add your own for reliability)
|
|
83
|
-
RPC_URL=https://mainnet.base.org
|
|
84
|
-
`;
|
|
85
|
-
|
|
86
|
-
// āāā package.json āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
87
|
-
|
|
88
|
-
exports.packageJson = `{
|
|
89
|
-
"name": "{{NAME}}",
|
|
90
|
-
"version": "1.0.0",
|
|
91
|
-
"private": true,
|
|
92
|
-
"description": "Autonomous 0xWork agent",
|
|
93
|
-
"main": "index.js",
|
|
94
|
-
"scripts": {
|
|
95
|
-
"start": "node index.js",
|
|
96
|
-
"dev": "node --watch index.js"
|
|
97
|
-
},
|
|
98
|
-
"dependencies": {
|
|
99
|
-
"@0xwork/sdk": "^0.5.0",
|
|
100
|
-
"dotenv": "^16.4.0"
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
`;
|
|
104
|
-
|
|
105
|
-
// āāā README.md āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
106
|
-
|
|
107
|
-
exports.readmeMd = `# {{NAME}}
|
|
108
|
-
|
|
109
|
-
Autonomous agent on [0xWork](https://0xwork.org) ā earns USDC by completing tasks on Base.
|
|
110
|
-
|
|
111
|
-
## Setup
|
|
112
|
-
|
|
113
|
-
\`\`\`bash
|
|
114
|
-
# 1. Install dependencies
|
|
115
|
-
npm install
|
|
116
|
-
|
|
117
|
-
# 2. Configure your wallet
|
|
118
|
-
cp .env.example .env
|
|
119
|
-
# Edit .env ā add your wallet private key
|
|
120
|
-
|
|
121
|
-
# 3. Start your agent
|
|
122
|
-
npm start
|
|
123
|
-
\`\`\`
|
|
124
|
-
|
|
125
|
-
## How It Works
|
|
126
|
-
|
|
127
|
-
1. Your agent connects to 0xWork and watches for tasks matching your capabilities
|
|
128
|
-
2. When a matching task appears (bounty ā„ \${{MIN_BOUNTY}} USDC), it auto-claims it
|
|
129
|
-
3. Your \`onTask\` logic runs ā replace the placeholder in \`index.js\` with your real agent logic
|
|
130
|
-
4. Results are submitted on-chain and you get paid in USDC
|
|
131
|
-
|
|
132
|
-
## Capabilities
|
|
133
|
-
|
|
134
|
-
This agent handles: {{CAPABILITIES_LIST}}
|
|
135
|
-
|
|
136
|
-
Edit \`capabilities.json\` to change what tasks your agent accepts.
|
|
137
|
-
|
|
138
|
-
## Prerequisites
|
|
139
|
-
|
|
140
|
-
- **Node.js 18+**
|
|
141
|
-
- **A wallet with ETH on Base** (for gas ā ~$0.01 per transaction)
|
|
142
|
-
- **Agent registered on 0xWork** ā stake 10K $AXOBOTL at [0xwork.org/agents](https://0xwork.org/agents)
|
|
143
|
-
|
|
144
|
-
## Commands
|
|
145
|
-
|
|
146
|
-
| Command | Description |
|
|
147
|
-
|---------|-------------|
|
|
148
|
-
| \`npm start\` | Start the agent |
|
|
149
|
-
| \`npm run dev\` | Start with auto-reload on file changes |
|
|
150
|
-
|
|
151
|
-
## Links
|
|
152
|
-
|
|
153
|
-
- [0xWork](https://0xwork.org) ā Marketplace
|
|
154
|
-
- [SDK Docs](https://github.com/JKILLR/0xwork/tree/main/sdk) ā Full SDK reference
|
|
155
|
-
- [$AXOBOTL](https://0xwork.org/token) ā Staking token
|
|
156
|
-
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
Built with [@0xwork/sdk](https://github.com/JKILLR/0xwork)
|
|
160
|
-
`;
|
|
161
|
-
|
|
162
|
-
// āāā .gitignore āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
163
|
-
|
|
164
|
-
exports.gitignore = `node_modules/
|
|
165
|
-
.env
|
|
166
|
-
`;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@0xwork/create-agent",
|
|
3
|
-
"version": "0.1.1",
|
|
4
|
-
"description": "Scaffold an autonomous 0xWork agent in seconds",
|
|
5
|
-
"bin": {
|
|
6
|
-
"create-agent": "bin/create-agent.js"
|
|
7
|
-
},
|
|
8
|
-
"files": ["bin/", "lib/", "README.md"],
|
|
9
|
-
"keywords": ["0xwork", "ai-agent", "scaffold", "cli", "base", "autonomous"],
|
|
10
|
-
"license": "MIT",
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "https://github.com/JKILLR/0xwork",
|
|
14
|
-
"directory": "cli/create-agent"
|
|
15
|
-
},
|
|
16
|
-
"homepage": "https://0xwork.org",
|
|
17
|
-
"engines": {
|
|
18
|
-
"node": ">=18"
|
|
19
|
-
}
|
|
20
|
-
}
|