@kroxy/kroxy 1.0.18 → 1.0.20

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,4 +1,4 @@
1
- import { createHash } from 'node:crypto';
1
+ import { demoDerivedAddress } from './src/utils/wallet.js';
2
2
  import { hireParams, executeHire } from './src/tools/hire.js';
3
3
  import { offerParams, executeOffer } from './src/tools/offer.js';
4
4
  import { reputationParams, executeReputation } from './src/tools/reputation.js';
@@ -10,10 +10,6 @@ import { disputeParams, executeDispute } from './src/tools/dispute.js';
10
10
  import { historyParams, executeHistory } from './src/tools/history.js';
11
11
  import { autoagentParams, executeAutoagent } from './src/tools/autoagent.js';
12
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
- }
17
13
  export default {
18
14
  id: 'kroxy',
19
15
  name: 'Kroxy',
@@ -38,11 +38,11 @@ export interface ConditionsDefinition {
38
38
  requiredPassRate: number;
39
39
  }
40
40
  export interface Condition {
41
- type: 'http_status' | 'json_field' | 'latency_ms' | 'uptime_percent';
41
+ type: 'http_status' | 'json_field' | 'latency_ms' | 'uptime_percent' | 'deliverable_quality';
42
42
  endpoint: string;
43
43
  field?: string;
44
- operator: 'eq' | 'gte' | 'lte' | 'contains';
45
- expected: string | number | boolean;
44
+ operator: 'eq' | 'gte' | 'lte' | 'gt' | 'lt' | 'contains';
45
+ expected: string | number | boolean | Record<string, unknown>;
46
46
  }
47
47
  export interface ReputationResult {
48
48
  walletAddress: string;
@@ -82,7 +82,7 @@ export declare function getAgents(filters?: {
82
82
  limit?: number;
83
83
  }): Promise<AgentProfile[]>;
84
84
  export declare function postJob(jobId: string, description: string, capability: string, budgetUsdc: number, conditionsJson: ConditionsDefinition, posterWallet: string): Promise<Job>;
85
- export declare function acceptBid(jobId: string, bidId: string, payerPrivateKey: string): Promise<{
85
+ export declare function acceptBid(jobId: string, bidId: string): Promise<{
86
86
  jobId: string;
87
87
  bidId: string;
88
88
  escrowId: string;
@@ -108,4 +108,4 @@ export declare function registerProvider(opts: {
108
108
  modelName?: string;
109
109
  }): Promise<AgentProfile>;
110
110
  export declare function pingApi(): Promise<boolean>;
111
- //# sourceMappingURL=client.d.ts.map
111
+ //# sourceMappingURL=client.d.ts.map
@@ -90,8 +90,11 @@ export function postJob(jobId, description, capability, budgetUsdc, conditionsJs
90
90
  conditionsJson,
91
91
  });
92
92
  }
93
- export function acceptBid(jobId, bidId, payerPrivateKey) {
94
- return apiPost(`/api/jobs/${jobId}/accept/${bidId}`, { payerPrivateKey });
93
+ export function acceptBid(jobId, bidId) {
94
+ // Security hardening: private keys are never sent over HTTP request bodies.
95
+ // Bid acceptance now uses server-side demo-mode flow only until client-side
96
+ // signing + registration is wired end-to-end.
97
+ return apiPost(`/api/jobs/${jobId}/accept/${bidId}`, {});
95
98
  }
96
99
  export function getJob(jobId) {
97
100
  return apiGet(`/api/jobs/${jobId}`);
@@ -2,8 +2,9 @@
2
2
  * kroxy_autoagent — Autonomous multi-step orchestrator.
3
3
  *
4
4
  * Takes a natural-language goal, decomposes it into 2–4 subtasks via Claude
5
- * (or a rule-based fallback if ANTHROPIC_API_KEY is unset), fires kroxy_hire
6
- * for each subtask sequentially, and returns a unified deliverable.
5
+ * through Lava's gateway (or a rule-based fallback if keys are unset), fires
6
+ * kroxy_hire for all subtasks in parallel, then synthesizes outputs into a
7
+ * unified deliverable via Lava.
7
8
  */
8
9
  export declare const autoagentParams: import("@sinclair/typebox").TObject<{
9
10
  goal: import("@sinclair/typebox").TString;
@@ -19,4 +20,4 @@ export declare function executeAutoagent(params: {
19
20
  }];
20
21
  details: unknown;
21
22
  }>;
22
- //# sourceMappingURL=autoagent.d.ts.map
23
+ //# sourceMappingURL=autoagent.d.ts.map
@@ -1,6 +1,7 @@
1
- import { createHash, randomBytes } from 'node:crypto';
1
+ import { randomBytes } from 'node:crypto';
2
2
  import { Type } from '@sinclair/typebox';
3
3
  import { findAgents, postJob, acceptBid, pollJob, } from '../client.js';
4
+ import { demoDerivedAddress } from '../utils/wallet.js';
4
5
  const DEFAULT_API_URL = 'https://api-production-1b45.up.railway.app';
5
6
  export const hireParams = Type.Object({
6
7
  task: Type.String({ description: 'What you want the hired agent to do, e.g. "Research the top AI payment startups"' }),
@@ -21,24 +22,39 @@ function detectCapability(task) {
21
22
  return 'research';
22
23
  }
23
24
  function buildConditions(nexusUrl, jobId) {
25
+ const apiBase = process.env.KROXY_API_URL ?? 'https://api-production-1b45.up.railway.app';
24
26
  return {
25
27
  version: '1.0',
26
28
  escrowId: '',
27
29
  conditions: [
30
+ // Provider liveness: agent endpoint must be healthy
28
31
  { type: 'http_status', endpoint: `${nexusUrl}/health`, operator: 'eq', expected: 200 },
32
+ // Delivery gate: job must reach COMPLETED status before escrow releases
29
33
  {
30
34
  type: 'json_field',
31
- endpoint: `${nexusUrl}/quality-check?jobId=${encodeURIComponent(jobId)}`,
32
- field: 'wordCount',
33
- operator: 'gte',
34
- expected: 100,
35
+ endpoint: `${apiBase}/api/jobs/${encodeURIComponent(jobId)}`,
36
+ field: 'status',
37
+ operator: 'eq',
38
+ expected: 'COMPLETED',
35
39
  },
40
+ // Quality gate: enforce structured, sourced, non-placeholder deliverable.
36
41
  {
37
- type: 'json_field',
38
- endpoint: `${nexusUrl}/quality-check?jobId=${encodeURIComponent(jobId)}`,
39
- field: 'confidence',
42
+ type: 'deliverable_quality',
43
+ endpoint: `${apiBase}/api/jobs/${encodeURIComponent(jobId)}`,
44
+ field: 'deliverable',
40
45
  operator: 'gte',
41
- expected: 0.7,
46
+ expected: {
47
+ minSummaryWords: 120,
48
+ minSummaryChars: 600,
49
+ minSentences: 3,
50
+ minKeyFindings: 3,
51
+ minFindingChars: 20,
52
+ minSources: 2,
53
+ minSourceDomains: 2,
54
+ minLexicalDiversity: 0.45,
55
+ requireCompletedStatus: true,
56
+ forbidPlaceholderPhrases: true,
57
+ },
42
58
  },
43
59
  ],
44
60
  windowSeconds: 120,
@@ -53,10 +69,6 @@ function formatDuration(startMs) {
53
69
  const mins = Math.floor(secs / 60);
54
70
  return `${mins}m ${secs % 60}s`;
55
71
  }
56
- function demoDerivedAddress() {
57
- const hash = createHash('sha256').update('kroxy-demo-wallet').digest('hex');
58
- return `0x${hash.slice(0, 40)}`;
59
- }
60
72
  function buildReceipt(opts) {
61
73
  const lines = [
62
74
  `✅ Job Complete — ${opts.task.slice(0, 60)}${opts.task.length > 60 ? '…' : ''}`,
@@ -86,13 +98,13 @@ export async function executeHire(params) {
86
98
  const nexusUrl = process.env.NEXUS_URL ?? (demoMode ? `${apiBase}/demo-agent` : 'http://localhost:3003');
87
99
  if (!wallet)
88
100
  throw new Error('KROXY_AGENT_WALLET is not configured. Run kroxy_setup to diagnose.');
89
- if (!demoMode && !privateKey)
90
- throw new Error('KROXY_AGENT_PRIVATE_KEY is not configured. Set KROXY_DEMO_MODE=1 to use demo mode without a real private key.');
101
+ if (!demoMode) {
102
+ throw new Error('Live-mode bid acceptance is disabled for security. Private keys are never sent over API calls. Set KROXY_DEMO_MODE=1.');
103
+ }
91
104
  const task = params.task;
92
105
  const maxPrice = params.maxPrice ?? 5.0;
93
106
  const minRep = params.minRep ?? 0;
94
107
  const capability = params.capability ?? detectCapability(task);
95
- const payerPrivateKey = privateKey ?? 'demo-private-key';
96
108
  const jobId = `job_${Date.now()}_${randomBytes(3).toString('hex')}`;
97
109
  const startMs = Date.now();
98
110
  // 1. Find matching agents
@@ -127,7 +139,7 @@ export async function executeHire(params) {
127
139
  `Increase maxPrice to $${bidPrice} or higher to accept this bid.`);
128
140
  }
129
141
  // 6. Accept bid — locks USDC in escrow on Base
130
- const escrowResult = await acceptBid(job.id, bid.id, payerPrivateKey);
142
+ const escrowResult = await acceptBid(job.id, bid.id);
131
143
  // 7. Poll for completion (up to 5 minutes)
132
144
  const completed = await pollJob(job.id, (j) => j.status === 'COMPLETED', 300_000);
133
145
  if (!completed) {
@@ -3,12 +3,14 @@ export declare const offerParams: import("@sinclair/typebox").TObject<{
3
3
  price: import("@sinclair/typebox").TNumber;
4
4
  endpoint: import("@sinclair/typebox").TString;
5
5
  name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
6
+ modelName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
6
7
  }>;
7
8
  export declare function executeOffer(params: {
8
9
  capability: string;
9
10
  price: number;
10
11
  endpoint: string;
11
12
  name?: string;
13
+ modelName?: string;
12
14
  }): Promise<{
13
15
  content: [{
14
16
  type: 'text';
@@ -16,4 +18,4 @@ export declare function executeOffer(params: {
16
18
  }];
17
19
  details: unknown;
18
20
  }>;
19
- //# sourceMappingURL=offer.d.ts.map
21
+ //# sourceMappingURL=offer.d.ts.map
@@ -1,15 +1,29 @@
1
1
  import { Type } from '@sinclair/typebox';
2
- import { createHash } from 'node:crypto';
3
2
  import { registerProvider } from '../client.js';
3
+ import { demoDerivedAddress } from '../utils/wallet.js';
4
4
  export const offerParams = Type.Object({
5
- capability: Type.String({ description: 'Capability to offer: research, writing, coding, analysis, etc.' }),
5
+ capability: Type.String({ description: 'Capability to offer: research, writing, coding, planning, analysis, etc.' }),
6
6
  price: Type.Number({ minimum: 0.01, description: 'Price per job in USDC, e.g. 2.50' }),
7
7
  endpoint: Type.String({ description: 'Public URL where your agent receives job webhooks, e.g. https://myagent.example.com' }),
8
8
  name: Type.Optional(Type.String({ description: 'Display name for your agent on the Kroxy job board' })),
9
+ modelName: Type.Optional(Type.String({ description: 'Model your agent runs, e.g. claude-sonnet-4-6, gpt-4o. Shown on the job board.' })),
9
10
  });
10
- function demoDerivedAddress() {
11
- const hash = createHash('sha256').update('kroxy-demo-wallet').digest('hex');
12
- return `0x${hash.slice(0, 40)}`;
11
+ /** Verify the endpoint is reachable before committing the registration. */
12
+ async function pingEndpoint(url) {
13
+ try {
14
+ const controller = new AbortController();
15
+ const timeout = setTimeout(() => controller.abort(), 5000);
16
+ let resp = await fetch(url, { method: 'HEAD', signal: controller.signal });
17
+ // Some webhook servers reject HEAD even when POST/GET are valid.
18
+ if (resp.status === 405 || resp.status === 501) {
19
+ resp = await fetch(url, { method: 'GET', signal: controller.signal });
20
+ }
21
+ clearTimeout(timeout);
22
+ return resp.status < 500;
23
+ }
24
+ catch {
25
+ return false;
26
+ }
13
27
  }
14
28
  export async function executeOffer(params) {
15
29
  const privateKey = process.env.KROXY_AGENT_PRIVATE_KEY;
@@ -17,26 +31,43 @@ export async function executeOffer(params) {
17
31
  const wallet = process.env.KROXY_AGENT_WALLET ?? (demoMode ? demoDerivedAddress() : undefined);
18
32
  if (!wallet)
19
33
  throw new Error('KROXY_AGENT_WALLET is not configured');
34
+ // Validate endpoint reachability before registering
35
+ const reachable = await pingEndpoint(params.endpoint);
36
+ if (!reachable) {
37
+ throw new Error(`Endpoint not reachable: ${params.endpoint}\nMake sure your agent is running and publicly accessible before registering.`);
38
+ }
20
39
  const agent = await registerProvider({
21
40
  walletAddress: wallet,
22
41
  name: params.name ?? 'MyAgent',
23
42
  endpoint: params.endpoint,
43
+ modelName: params.modelName,
24
44
  capabilities: [params.capability],
25
45
  pricingUsdc: params.price,
26
46
  });
47
+ const lines = [
48
+ `✅ Agent Registered on Kroxy`,
49
+ ``,
50
+ `Wallet: ${agent.walletAddress ?? wallet}`,
51
+ `Name: ${agent.name ?? params.name ?? 'MyAgent'}`,
52
+ `Capability: ${(agent.capabilities ?? [params.capability]).join(', ')}`,
53
+ `Price: $${agent.pricingUsdc ?? params.price} USDC / job`,
54
+ `Endpoint: ${params.endpoint}`,
55
+ ];
56
+ if (params.modelName) {
57
+ lines.push(`Model: ${params.modelName}`);
58
+ }
59
+ lines.push(``, `You are now listed on the Kroxy job board. Incoming jobs will be sent as POST webhooks to your endpoint.`);
27
60
  const result = {
28
61
  registered: true,
29
62
  walletAddress: agent.walletAddress ?? wallet,
30
63
  name: agent.name ?? params.name,
31
64
  capabilities: agent.capabilities ?? [params.capability],
32
65
  pricingUsdc: agent.pricingUsdc ?? params.price,
66
+ modelName: params.modelName,
33
67
  endpoint: params.endpoint,
34
68
  };
35
69
  return {
36
- content: [{
37
- type: 'text',
38
- text: JSON.stringify(result, null, 2),
39
- }],
70
+ content: [{ type: 'text', text: lines.join('\n') }],
40
71
  details: result,
41
72
  };
42
73
  }
@@ -16,19 +16,27 @@ export async function executeReputation(params) {
16
16
  score >= 60 ? 'Good — established track record' :
17
17
  score >= 20 ? 'New — building reputation' :
18
18
  'Low — exercise caution';
19
+ const successCount = rep.successCount ?? 0;
20
+ const disputeCount = rep.disputeCount ?? 0;
21
+ const totalEarned = rep.totalEarned ?? '0';
22
+ const lines = [
23
+ `Reputation: ${walletAddress}`,
24
+ ``,
25
+ `Score: ${score}/100 — ${interpretation}`,
26
+ `Jobs won: ${successCount}`,
27
+ `Disputes: ${disputeCount}`,
28
+ `Total earned: $${totalEarned} USDC`,
29
+ ];
19
30
  const result = {
20
31
  address: walletAddress,
21
32
  score,
22
- successCount: rep.successCount ?? 0,
23
- disputeCount: rep.disputeCount ?? 0,
24
- totalEarned: rep.totalEarned ?? '0',
33
+ successCount,
34
+ disputeCount,
35
+ totalEarned,
25
36
  interpretation,
26
37
  };
27
38
  return {
28
- content: [{
29
- type: 'text',
30
- text: JSON.stringify(result, null, 2),
31
- }],
39
+ content: [{ type: 'text', text: lines.join('\n') }],
32
40
  details: result,
33
41
  };
34
42
  }
@@ -0,0 +1,10 @@
1
+ import { createHash } from 'node:crypto';
2
+ /**
3
+ * Deterministic demo wallet address derived from a fixed seed.
4
+ * Used in demo mode when no real wallet is configured.
5
+ */
6
+ export function demoDerivedAddress() {
7
+ const hash = createHash('sha256').update('kroxy-demo-wallet').digest('hex');
8
+ return `0x${hash.slice(0, 40)}`;
9
+ }
10
+ //# sourceMappingURL=wallet.js.map
package/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { OpenClawPluginApi } from 'openclaw/plugin-sdk';
2
- import { createHash } from 'node:crypto';
2
+ import { demoDerivedAddress } from './src/utils/wallet.js';
3
3
  import { hireParams, executeHire } from './src/tools/hire.js';
4
4
  import { offerParams, executeOffer } from './src/tools/offer.js';
5
5
  import { reputationParams, executeReputation } from './src/tools/reputation.js';
@@ -24,11 +24,6 @@ type AutoagentToolParams = Parameters<typeof executeAutoagent>[0];
24
24
 
25
25
  const DEFAULT_API_URL = 'https://api-production-1b45.up.railway.app';
26
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
-
32
27
  export default {
33
28
  id: 'kroxy',
34
29
  name: 'Kroxy',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kroxy/kroxy",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "type": "module",
5
5
  "description": "Trustless agent-to-agent payments via USDC escrow on Base blockchain",
6
6
  "license": "MIT",
@@ -1,19 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { createHash } from 'node:crypto';
4
3
  import fs from 'node:fs';
5
4
  import os from 'node:os';
6
5
  import path from 'node:path';
7
6
  import process from 'node:process';
8
7
  import readline from 'node:readline/promises';
8
+ import { demoDerivedAddress } from '../dist/src/utils/wallet.js';
9
9
 
10
10
  const DEFAULT_API_URL = 'https://api-production-1b45.up.railway.app';
11
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
12
  function resolveConfigPath() {
18
13
  const explicit = process.env.OPENCLAW_CONFIG_PATH?.trim();
19
14
  if (explicit) return explicit;