@kroxy/kroxy 1.0.16 → 1.0.17

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/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import { hireParams, executeHire } from './src/tools/hire.js';
2
3
  import { offerParams, executeOffer } from './src/tools/offer.js';
3
4
  import { reputationParams, executeReputation } from './src/tools/reputation.js';
@@ -8,6 +9,11 @@ import { browseParams, executeBrowse } from './src/tools/browse.js';
8
9
  import { disputeParams, executeDispute } from './src/tools/dispute.js';
9
10
  import { historyParams, executeHistory } from './src/tools/history.js';
10
11
  import { autoagentParams, executeAutoagent } from './src/tools/autoagent.js';
12
+ const DEFAULT_API_URL = 'https://api-production-1b45.up.railway.app';
13
+ function demoDerivedAddress() {
14
+ const hash = createHash('sha256').update('kroxy-demo-wallet').digest('hex');
15
+ return `0x${hash.slice(0, 40)}`;
16
+ }
11
17
  export default {
12
18
  id: 'kroxy',
13
19
  name: 'Kroxy',
@@ -25,6 +31,13 @@ export default {
25
31
  process.env.KROXY_DEMO_MODE = cfg.KROXY_DEMO_MODE;
26
32
  if (cfg.NEXUS_URL)
27
33
  process.env.NEXUS_URL = cfg.NEXUS_URL;
34
+ if (!process.env.KROXY_API_URL)
35
+ process.env.KROXY_API_URL = DEFAULT_API_URL;
36
+ if (!process.env.KROXY_DEMO_MODE && !process.env.KROXY_AGENT_PRIVATE_KEY)
37
+ process.env.KROXY_DEMO_MODE = '1';
38
+ if (process.env.KROXY_DEMO_MODE === '1' && !process.env.KROXY_AGENT_WALLET) {
39
+ process.env.KROXY_AGENT_WALLET = demoDerivedAddress();
40
+ }
28
41
  // ── Setup / Onboarding ────────────────────────────────────────────────────
29
42
  // Run this first to check configuration and get guided setup instructions.
30
43
  api.registerTool({
@@ -139,4 +152,4 @@ export default {
139
152
  }, { optional: true });
140
153
  },
141
154
  };
142
- //# sourceMappingURL=index.js.map
155
+ //# sourceMappingURL=index.js.map
@@ -4,8 +4,9 @@
4
4
  * so runtime-injected env vars are always used.
5
5
  */
6
6
  import { fetchWithRetry } from './utils/fetchWithRetry.js';
7
+ const DEFAULT_API_URL = 'https://api-production-1b45.up.railway.app';
7
8
  function apiBase() {
8
- return process.env.KROXY_API_URL ?? 'http://localhost:3001';
9
+ return process.env.KROXY_API_URL ?? DEFAULT_API_URL;
9
10
  }
10
11
  function authHeaders() {
11
12
  const key = process.env.KROXY_API_KEY ?? '';
@@ -149,4 +150,4 @@ export async function pingApi() {
149
150
  return false;
150
151
  }
151
152
  }
152
- //# sourceMappingURL=client.js.map
153
+ //# sourceMappingURL=client.js.map
@@ -1,6 +1,7 @@
1
- import { randomBytes } from 'node:crypto';
1
+ import { createHash, randomBytes } from 'node:crypto';
2
2
  import { Type } from '@sinclair/typebox';
3
3
  import { findAgents, postJob, acceptBid, pollJob, } from '../client.js';
4
+ const DEFAULT_API_URL = 'https://api-production-1b45.up.railway.app';
4
5
  export const hireParams = Type.Object({
5
6
  task: Type.String({ description: 'What you want the hired agent to do, e.g. "Research the top AI payment startups"' }),
6
7
  maxPrice: Type.Optional(Type.Number({ minimum: 0.01, description: 'Maximum USDC budget, default 5.00' })),
@@ -49,6 +50,10 @@ function formatDuration(startMs) {
49
50
  const mins = Math.floor(secs / 60);
50
51
  return `${mins}m ${secs % 60}s`;
51
52
  }
53
+ function demoDerivedAddress() {
54
+ const hash = createHash('sha256').update('kroxy-demo-wallet').digest('hex');
55
+ return `0x${hash.slice(0, 40)}`;
56
+ }
52
57
  function buildReceipt(opts) {
53
58
  const lines = [
54
59
  `✅ Job Complete — ${opts.task.slice(0, 60)}${opts.task.length > 60 ? '…' : ''}`,
@@ -70,10 +75,10 @@ function buildReceipt(opts) {
70
75
  return lines.join('\n');
71
76
  }
72
77
  export async function executeHire(params) {
73
- const wallet = process.env.KROXY_AGENT_WALLET;
74
78
  const privateKey = process.env.KROXY_AGENT_PRIVATE_KEY;
75
- const demoMode = process.env.KROXY_DEMO_MODE === '1';
76
- const apiBase = process.env.KROXY_API_URL ?? 'http://localhost:3001';
79
+ const demoMode = process.env.KROXY_DEMO_MODE === '1' || (!process.env.KROXY_DEMO_MODE && !privateKey);
80
+ const wallet = process.env.KROXY_AGENT_WALLET ?? (demoMode ? demoDerivedAddress() : undefined);
81
+ const apiBase = process.env.KROXY_API_URL ?? DEFAULT_API_URL;
77
82
  // In demo mode, point at the embedded demo agent in the API if NEXUS_URL not explicitly set
78
83
  const nexusUrl = process.env.NEXUS_URL ?? (demoMode ? `${apiBase}/demo-agent` : 'http://localhost:3003');
79
84
  if (!wallet)
@@ -160,4 +165,4 @@ export async function executeHire(params) {
160
165
  details,
161
166
  };
162
167
  }
163
- //# sourceMappingURL=hire.js.map
168
+ //# sourceMappingURL=hire.js.map
@@ -1,4 +1,5 @@
1
1
  import { Type } from '@sinclair/typebox';
2
+ import { createHash } from 'node:crypto';
2
3
  import { registerProvider } from '../client.js';
3
4
  export const offerParams = Type.Object({
4
5
  capability: Type.String({ description: 'Capability to offer: research, writing, coding, analysis, etc.' }),
@@ -6,8 +7,14 @@ export const offerParams = Type.Object({
6
7
  endpoint: Type.String({ description: 'Public URL where your agent receives job webhooks, e.g. https://myagent.example.com' }),
7
8
  name: Type.Optional(Type.String({ description: 'Display name for your agent on the Kroxy job board' })),
8
9
  });
10
+ function demoDerivedAddress() {
11
+ const hash = createHash('sha256').update('kroxy-demo-wallet').digest('hex');
12
+ return `0x${hash.slice(0, 40)}`;
13
+ }
9
14
  export async function executeOffer(params) {
10
- const wallet = process.env.KROXY_AGENT_WALLET;
15
+ const privateKey = process.env.KROXY_AGENT_PRIVATE_KEY;
16
+ const demoMode = process.env.KROXY_DEMO_MODE === '1' || (!process.env.KROXY_DEMO_MODE && !privateKey);
17
+ const wallet = process.env.KROXY_AGENT_WALLET ?? (demoMode ? demoDerivedAddress() : undefined);
11
18
  if (!wallet)
12
19
  throw new Error('KROXY_AGENT_WALLET is not configured');
13
20
  const agent = await registerProvider({
@@ -33,4 +40,4 @@ export async function executeOffer(params) {
33
40
  details: result,
34
41
  };
35
42
  }
36
- //# sourceMappingURL=offer.js.map
43
+ //# sourceMappingURL=offer.js.map
@@ -2,6 +2,7 @@ import { Type } from '@sinclair/typebox';
2
2
  import { createHash } from 'node:crypto';
3
3
  import { pingApi } from '../client.js';
4
4
  export const setupParams = Type.Object({});
5
+ const DEFAULT_API_URL = 'https://api-production-1b45.up.railway.app';
5
6
  function icon(s) {
6
7
  return s === 'ok' ? '✅' : s === 'warn' ? '⚠️ ' : '❌';
7
8
  }
@@ -19,11 +20,11 @@ function demoDerivedAddress() {
19
20
  return `0x${hash.slice(0, 40)}`;
20
21
  }
21
22
  export async function executeSetup(_params) {
22
- const apiUrl = process.env.KROXY_API_URL ?? 'http://localhost:3001';
23
+ const apiUrl = process.env.KROXY_API_URL ?? DEFAULT_API_URL;
23
24
  const apiKey = process.env.KROXY_API_KEY;
24
25
  const wallet = process.env.KROXY_AGENT_WALLET;
25
26
  const privateKey = process.env.KROXY_AGENT_PRIVATE_KEY;
26
- const demoMode = process.env.KROXY_DEMO_MODE === '1';
27
+ const demoMode = process.env.KROXY_DEMO_MODE === '1' || (!process.env.KROXY_DEMO_MODE && !privateKey);
27
28
  const nexusUrl = process.env.NEXUS_URL;
28
29
  const checks = [];
29
30
  let blockingIssues = 0;
@@ -55,10 +56,13 @@ export async function executeSetup(_params) {
55
56
  else {
56
57
  checks.push({
57
58
  item: 'API key (KROXY_API_KEY)',
58
- status: 'error',
59
- hint: 'Required for posting jobs and hiring agents. Set in plugin config.',
59
+ status: demoMode ? 'warn' : 'error',
60
+ hint: demoMode
61
+ ? 'Optional in demo mode. Add an API key for higher rate limits and live usage.'
62
+ : 'Required for posting jobs and hiring agents. Set in plugin config.',
60
63
  });
61
- blockingIssues++;
64
+ if (!demoMode)
65
+ blockingIssues++;
62
66
  }
63
67
  // 4. Agent wallet
64
68
  let suggestedWallet;
@@ -138,4 +142,4 @@ export async function executeSetup(_params) {
138
142
  details: result,
139
143
  };
140
144
  }
141
- //# sourceMappingURL=setup.js.map
145
+ //# sourceMappingURL=setup.js.map
package/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { OpenClawPluginApi } from 'openclaw/plugin-sdk';
2
+ import { createHash } from 'node:crypto';
2
3
  import { hireParams, executeHire } from './src/tools/hire.js';
3
4
  import { offerParams, executeOffer } from './src/tools/offer.js';
4
5
  import { reputationParams, executeReputation } from './src/tools/reputation.js';
@@ -21,6 +22,13 @@ type DisputeToolParams = Parameters<typeof executeDispute>[0];
21
22
  type HistoryToolParams = Parameters<typeof executeHistory>[0];
22
23
  type AutoagentToolParams = Parameters<typeof executeAutoagent>[0];
23
24
 
25
+ const DEFAULT_API_URL = 'https://api-production-1b45.up.railway.app';
26
+
27
+ function demoDerivedAddress(): string {
28
+ const hash = createHash('sha256').update('kroxy-demo-wallet').digest('hex');
29
+ return `0x${hash.slice(0, 40)}`;
30
+ }
31
+
24
32
  export default {
25
33
  id: 'kroxy',
26
34
  name: 'Kroxy',
@@ -33,6 +41,12 @@ export default {
33
41
  if (cfg.KROXY_DEMO_MODE) process.env.KROXY_DEMO_MODE = cfg.KROXY_DEMO_MODE;
34
42
  if (cfg.NEXUS_URL) process.env.NEXUS_URL = cfg.NEXUS_URL;
35
43
 
44
+ if (!process.env.KROXY_API_URL) process.env.KROXY_API_URL = DEFAULT_API_URL;
45
+ if (!process.env.KROXY_DEMO_MODE && !process.env.KROXY_AGENT_PRIVATE_KEY) process.env.KROXY_DEMO_MODE = '1';
46
+ if (process.env.KROXY_DEMO_MODE === '1' && !process.env.KROXY_AGENT_WALLET) {
47
+ process.env.KROXY_AGENT_WALLET = demoDerivedAddress();
48
+ }
49
+
36
50
  // ── Setup / Onboarding ────────────────────────────────────────────────────
37
51
  // Run this first to check configuration and get guided setup instructions.
38
52
  api.registerTool({
@@ -8,12 +8,18 @@
8
8
  "type": "object",
9
9
  "additionalProperties": false,
10
10
  "properties": {
11
- "KROXY_API_URL": { "type": "string" },
11
+ "KROXY_API_URL": {
12
+ "type": "string",
13
+ "default": "https://api-production-1b45.up.railway.app"
14
+ },
12
15
  "KROXY_API_KEY": { "type": "string" },
13
16
  "KROXY_AGENT_WALLET": { "type": "string" },
14
17
  "KROXY_AGENT_PRIVATE_KEY": { "type": "string" },
15
18
  "NEXUS_URL": { "type": "string" },
16
- "KROXY_DEMO_MODE": { "type": "string" }
19
+ "KROXY_DEMO_MODE": {
20
+ "type": "string",
21
+ "default": "1"
22
+ }
17
23
  },
18
24
  "required": []
19
25
  },
@@ -27,4 +33,4 @@
27
33
  "sensitive": true
28
34
  }
29
35
  }
30
- }
36
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kroxy/kroxy",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "type": "module",
5
5
  "description": "Trustless agent-to-agent payments via USDC escrow on Base blockchain",
6
6
  "license": "MIT",
@@ -17,7 +17,8 @@
17
17
  "files": [
18
18
  "dist",
19
19
  "index.ts",
20
- "openclaw.plugin.json"
20
+ "openclaw.plugin.json",
21
+ "scripts"
21
22
  ],
22
23
  "dependencies": {
23
24
  "@sinclair/typebox": "^0.32.0"
@@ -29,8 +30,13 @@
29
30
  "peerDependencies": {
30
31
  "openclaw": "*"
31
32
  },
33
+ "bin": {
34
+ "kroxy-setup": "./scripts/setup-openclaw.mjs"
35
+ },
32
36
  "scripts": {
33
37
  "build": "tsc",
34
- "dev": "tsc --watch"
38
+ "dev": "tsc --watch",
39
+ "postinstall": "node ./scripts/setup-openclaw.mjs --postinstall",
40
+ "setup:openclaw": "node ./scripts/setup-openclaw.mjs"
35
41
  }
36
42
  }
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createHash } from 'node:crypto';
4
+ import fs from 'node:fs';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import process from 'node:process';
8
+ import readline from 'node:readline/promises';
9
+
10
+ const DEFAULT_API_URL = 'https://api-production-1b45.up.railway.app';
11
+
12
+ function demoDerivedAddress() {
13
+ const hash = createHash('sha256').update('kroxy-demo-wallet').digest('hex');
14
+ return `0x${hash.slice(0, 40)}`;
15
+ }
16
+
17
+ function resolveConfigPath() {
18
+ const explicit = process.env.OPENCLAW_CONFIG_PATH?.trim();
19
+ if (explicit) return explicit;
20
+ const stateDir = process.env.OPENCLAW_STATE_DIR?.trim() || path.join(os.homedir(), '.openclaw');
21
+ return path.join(stateDir, 'openclaw.json');
22
+ }
23
+
24
+ function ensureObject(parent, key) {
25
+ const current = parent[key];
26
+ if (!current || typeof current !== 'object' || Array.isArray(current)) {
27
+ parent[key] = {};
28
+ }
29
+ return parent[key];
30
+ }
31
+
32
+ async function askYesNo(rl, question, defaultYes = true) {
33
+ const suffix = defaultYes ? ' [Y/n] ' : ' [y/N] ';
34
+ const answer = (await rl.question(`${question}${suffix}`)).trim().toLowerCase();
35
+ if (!answer) return defaultYes;
36
+ if (['y', 'yes'].includes(answer)) return true;
37
+ if (['n', 'no'].includes(answer)) return false;
38
+ return defaultYes;
39
+ }
40
+
41
+ function parseJsonConfig(raw, configPath) {
42
+ try {
43
+ const parsed = JSON.parse(raw);
44
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
45
+ throw new Error('top-level JSON value must be an object');
46
+ }
47
+ return parsed;
48
+ } catch (err) {
49
+ throw new Error(
50
+ `Could not parse ${configPath} as strict JSON (${String(err)}).\n` +
51
+ 'Run: openclaw config set plugins.entries.kroxy.config.KROXY_API_URL ' +
52
+ `"${DEFAULT_API_URL}"`
53
+ );
54
+ }
55
+ }
56
+
57
+ async function runSetup({ postinstall }) {
58
+ const configPath = resolveConfigPath();
59
+ const commandHint = 'node ~/.openclaw/extensions/kroxy/scripts/setup-openclaw.mjs';
60
+
61
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
62
+ if (postinstall) {
63
+ console.log(`[kroxy] Skipping interactive setup (non-interactive terminal). Run ${commandHint}`);
64
+ }
65
+ return 0;
66
+ }
67
+
68
+ if (!fs.existsSync(configPath)) {
69
+ console.log(`[kroxy] OpenClaw config not found at ${configPath}.`);
70
+ console.log('[kroxy] Run OpenClaw once, then run this setup wizard again.');
71
+ return 0;
72
+ }
73
+
74
+ const raw = fs.readFileSync(configPath, 'utf8');
75
+ const cfg = parseJsonConfig(raw, configPath);
76
+ const plugins = ensureObject(cfg, 'plugins');
77
+ const entries = ensureObject(plugins, 'entries');
78
+ const kroxy = ensureObject(entries, 'kroxy');
79
+ const pluginConfig = ensureObject(kroxy, 'config');
80
+
81
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
82
+ try {
83
+ const start = await askYesNo(rl, 'Configure Kroxy in OpenClaw now?', true);
84
+ if (!start) return 0;
85
+
86
+ if (await askYesNo(rl, `Set KROXY_API_URL to ${DEFAULT_API_URL}?`, !pluginConfig.KROXY_API_URL)) {
87
+ pluginConfig.KROXY_API_URL = DEFAULT_API_URL;
88
+ }
89
+
90
+ const defaultDemo = pluginConfig.KROXY_DEMO_MODE !== '0';
91
+ if (await askYesNo(rl, 'Enable demo mode by default (recommended for first run)?', defaultDemo)) {
92
+ pluginConfig.KROXY_DEMO_MODE = '1';
93
+ } else if (pluginConfig.KROXY_DEMO_MODE === '1') {
94
+ delete pluginConfig.KROXY_DEMO_MODE;
95
+ }
96
+
97
+ if (pluginConfig.KROXY_DEMO_MODE === '1') {
98
+ const shouldSetDemoWallet = await askYesNo(
99
+ rl,
100
+ 'Auto-set a demo wallet address for KROXY_AGENT_WALLET?',
101
+ !pluginConfig.KROXY_AGENT_WALLET
102
+ );
103
+ if (shouldSetDemoWallet) {
104
+ pluginConfig.KROXY_AGENT_WALLET = pluginConfig.KROXY_AGENT_WALLET || demoDerivedAddress();
105
+ }
106
+ }
107
+
108
+ const setApiKeyNow = await askYesNo(rl, 'Set KROXY_API_KEY now?', false);
109
+ if (setApiKeyNow) {
110
+ const key = (await rl.question('Paste KROXY_API_KEY: ')).trim();
111
+ if (key) pluginConfig.KROXY_API_KEY = key;
112
+ }
113
+
114
+ const save = await askYesNo(rl, `Save changes to ${configPath}?`, true);
115
+ if (!save) {
116
+ console.log('[kroxy] Setup canceled; no changes saved.');
117
+ return 0;
118
+ }
119
+
120
+ fs.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}\n`, 'utf8');
121
+ console.log('[kroxy] Saved OpenClaw config for plugin "kroxy".');
122
+ console.log('[kroxy] Restart the gateway to load the new config.');
123
+ return 0;
124
+ } finally {
125
+ rl.close();
126
+ }
127
+ }
128
+
129
+ const postinstall = process.argv.includes('--postinstall');
130
+ runSetup({ postinstall }).then(
131
+ (code) => {
132
+ process.exitCode = code;
133
+ },
134
+ (err) => {
135
+ console.error(`[kroxy] Setup wizard failed: ${String(err)}`);
136
+ process.exitCode = 1;
137
+ }
138
+ );