@xpr-agents/openclaw 0.6.1 → 0.7.1

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.
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "outDir": "./dist",
6
+ "rootDir": "./src",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "resolveJsonModule": true,
11
+ "declaration": false
12
+ },
13
+ "include": ["src/**/*.ts"]
14
+ }
@@ -25,6 +25,35 @@ You have powerful creative capabilities for delivering job results:
25
25
  **Images/Media from the web:**
26
26
  - Use `web_search` to find suitable content, then `store_deliverable` with source_url
27
27
 
28
+ **3D models (.glb / .gltf):**
29
+ - `store_deliverable` with content_type "model/gltf-binary" (.glb) or "model/gltf+json" (.gltf)
30
+ and a `source_url` — the model is downloaded and pinned to IPFS
31
+ - A source_url ending .glb/.gltf is recognised as a model even without content_type
32
+ - The job board renders it in an interactive three.js viewer the client can orbit, zoom and pan
33
+ - Shipping a model plus a preview image or a written summary is one deliverable with several
34
+ files, so pin each file with its own `store_deliverable` call and then deliver a manifest:
35
+
36
+ ```json
37
+ {"v":1,"files":[
38
+ {"name":"scene.glb","uri":"https://<gateway>/ipfs/<cid>","type":"model/gltf-binary"},
39
+ {"name":"preview.png","uri":"https://<gateway>/ipfs/<cid2>","type":"image/png"}
40
+ ],"note":"how it was made"}
41
+ ```
42
+
43
+ Give every model entry `"type":"model/gltf-binary"` (or `model/gltf+json`). That `type` is what
44
+ the viewer keys off; without it the file only renders if its URI still ends in .glb/.gltf.
45
+ Pass the manifest JSON string itself as `evidence_uri` to `xpr_deliver_job` — do not try to
46
+ store the manifest with `store_deliverable`.
47
+
48
+ **What renders on the job page (put the substance in these):**
49
+ - `text/markdown` / `text/plain` — headings, lists and tables, rendered in place.
50
+ - `text/csv` — a sortable table. Always include a header row.
51
+ - `application/json` — a collapsible tree, so a metrics file is readable, not just downloadable.
52
+ - `audio/*` and `video/*` — an inline player.
53
+ - `note` is a one-paragraph caption, not the report. Do not put the deliverable there.
54
+ - Give every entry an accurate `type`: it is what the page keys off, and a pinned
55
+ `/ipfs/<cid>` URL usually has no extension to fall back on.
56
+
28
57
  **Code repositories:**
29
58
  - `create_github_repo` with all source files — creates a public GitHub repo
30
59
 
@@ -68,6 +68,54 @@ async function uploadBinaryToIpfs(buffer, filename, mimeType) {
68
68
  }
69
69
  return null;
70
70
  }
71
+ const MODEL_CONTENT_TYPES = ['model/gltf-binary', 'model/gltf+json'];
72
+ const MODEL_EXT_RE = /\.(glb|gltf)(?:$|[?#])/i;
73
+ const GENERIC_BINARY_TYPES = ['', 'application/octet-stream', 'binary/octet-stream', 'application/binary'];
74
+ /**
75
+ * Extension to pin a file under. `mimeType.split('/')[1]` is wrong for the model types —
76
+ * it yields "gltf-binary" — and the job board keys off the extension when a manifest
77
+ * omits `type`, so a GLB must land as `.glb`.
78
+ */
79
+ const EXTENSION_BY_MIME = {
80
+ 'model/gltf-binary': 'glb',
81
+ 'model/gltf+json': 'gltf',
82
+ 'application/pdf': 'pdf',
83
+ 'image/jpeg': 'jpg',
84
+ 'image/png': 'png',
85
+ 'image/webp': 'webp',
86
+ 'image/gif': 'gif',
87
+ 'image/svg+xml': 'svg',
88
+ 'audio/mpeg': 'mp3',
89
+ 'audio/wav': 'wav',
90
+ 'video/mp4': 'mp4',
91
+ 'video/webm': 'webm',
92
+ };
93
+ function isGenericBinaryType(mimeType) {
94
+ return GENERIC_BINARY_TYPES.includes((mimeType || '').split(';')[0].trim().toLowerCase());
95
+ }
96
+ /** A 3D deliverable, whether declared by content_type or implied by the source URL. */
97
+ function isModelDeliverable(contentType, sourceUrl) {
98
+ if (MODEL_CONTENT_TYPES.includes(contentType))
99
+ return true;
100
+ return Boolean(sourceUrl && MODEL_EXT_RE.test(sourceUrl.split('?')[0]));
101
+ }
102
+ function modelMimeFor(contentType, sourceUrl) {
103
+ if (MODEL_CONTENT_TYPES.includes(contentType))
104
+ return contentType;
105
+ return /\.gltf(?:$|[?#])/i.test((sourceUrl || '').split('?')[0]) ? 'model/gltf+json' : 'model/gltf-binary';
106
+ }
107
+ function extensionFor(mimeType, sourceUrl, filename) {
108
+ if (filename && filename.includes('.'))
109
+ return filename.split('.').pop().toLowerCase();
110
+ const mapped = EXTENSION_BY_MIME[mimeType];
111
+ if (mapped)
112
+ return mapped;
113
+ const path = (sourceUrl || '').split('?')[0].split('#')[0];
114
+ const fromUrl = path.includes('.') ? path.split('.').pop() : '';
115
+ if (fromUrl && fromUrl.length <= 5 && !fromUrl.includes('/'))
116
+ return fromUrl.toLowerCase();
117
+ return mimeType.split('/')[1]?.split('+')[0] || 'bin';
118
+ }
71
119
  const MAX_DOWNLOAD_SIZE = 50 * 1024 * 1024;
72
120
  async function downloadFromUrl(url) {
73
121
  if (!/^https?:\/\//.test(url))
@@ -386,6 +434,9 @@ function creativeSkill(api) {
386
434
  ' Images referenced as ![alt](url) in the Markdown are downloaded and embedded in the PDF.',
387
435
  ' Do NOT include <cite> or other HTML tags in the content — use clean Markdown only.',
388
436
  ' image/*, audio/*, video/* — downloads source_url and uploads binary to IPFS',
437
+ ' model/gltf-binary (.glb), model/gltf+json (.gltf) — downloads source_url and uploads the 3D',
438
+ ' model to IPFS. The job board renders it in an interactive three.js viewer.',
439
+ ' A source_url ending .glb/.gltf is treated as a model even with no content_type.',
389
440
  ' text/csv, text/plain, text/html, application/json — uploads the text as a file on IPFS (the URL serves the raw file)',
390
441
  'Do NOT store a delivery manifest with this tool: pass the manifest JSON string itself as evidence_uri to xpr_deliver_job.',
391
442
  ].join('\n'),
@@ -396,8 +447,8 @@ function creativeSkill(api) {
396
447
  job_id: { type: 'number', description: 'Job ID' },
397
448
  content: { type: 'string', description: 'Full deliverable content (markdown, text, CSV, etc.). For media types, can be empty if source_url is provided.' },
398
449
  content_type: { type: 'string', description: 'MIME type: text/markdown (default), application/pdf, image/png, audio/mpeg, video/mp4, text/csv, etc.' },
399
- source_url: { type: 'string', description: 'URL to download binary content from (for image/audio/video). The file is downloaded and uploaded to IPFS.' },
400
- filename: { type: 'string', description: 'Optional filename for the deliverable (e.g. "report.pdf")' },
450
+ source_url: { type: 'string', description: 'URL to download binary content from (for image/audio/video/3D model). The file is downloaded and uploaded to IPFS.' },
451
+ filename: { type: 'string', description: 'Optional filename for the deliverable (e.g. "report.pdf", "scene.glb"). The extension matters — it is how the job board identifies the file when a manifest omits its type.' },
401
452
  },
402
453
  },
403
454
  handler: async ({ job_id, content, content_type, source_url, filename }) => {
@@ -427,23 +478,33 @@ function creativeSkill(api) {
427
478
  return { stored: false, error: `PDF generation failed: ${err.message}` };
428
479
  }
429
480
  }
430
- if (ct.startsWith('image/') || ct.startsWith('audio/') || ct.startsWith('video/') || ct === 'application/octet-stream') {
481
+ const isModel = isModelDeliverable(ct, source_url);
482
+ if (isModel || ct.startsWith('image/') || ct.startsWith('audio/') || ct.startsWith('video/') || ct === 'application/octet-stream') {
431
483
  let buffer = null;
432
484
  let mimeType = ct;
433
485
  if (source_url) {
434
486
  const downloaded = await downloadFromUrl(source_url);
435
487
  if (downloaded) {
436
488
  buffer = downloaded.buffer;
437
- mimeType = downloaded.mimeType || ct;
489
+ // Model hosts routinely serve GLBs as application/octet-stream, so a generic
490
+ // response type must not overwrite the specific type we already worked out.
491
+ if (isModel)
492
+ mimeType = modelMimeFor(ct, source_url);
493
+ else if (!isGenericBinaryType(downloaded.mimeType))
494
+ mimeType = downloaded.mimeType;
495
+ else
496
+ mimeType = ct;
438
497
  }
439
498
  }
440
499
  else if (content) {
441
500
  buffer = Buffer.from(content, 'base64');
501
+ if (isModel)
502
+ mimeType = modelMimeFor(ct, source_url);
442
503
  }
443
504
  if (!buffer)
444
505
  return { stored: false, error: 'Failed to obtain binary content. Provide source_url for media types.' };
445
506
  setDeliverable(job_id, { content: source_url || '[binary]', content_type: mimeType, created_at: ts });
446
- const ext = mimeType.split('/')[1]?.split('+')[0] || 'bin';
507
+ const ext = extensionFor(mimeType, source_url, filename);
447
508
  const url = await uploadBinaryToIpfs(buffer, filename || `job-${job_id}.${ext}`, mimeType);
448
509
  if (url) {
449
510
  console.log(`[deliverable] Job ${job_id} ${mimeType} → IPFS: ${url}`);
@@ -79,6 +79,55 @@ async function uploadBinaryToIpfs(buffer: Buffer, filename: string, mimeType: st
79
79
  return null;
80
80
  }
81
81
 
82
+ const MODEL_CONTENT_TYPES = ['model/gltf-binary', 'model/gltf+json'];
83
+ const MODEL_EXT_RE = /\.(glb|gltf)(?:$|[?#])/i;
84
+ const GENERIC_BINARY_TYPES = ['', 'application/octet-stream', 'binary/octet-stream', 'application/binary'];
85
+
86
+ /**
87
+ * Extension to pin a file under. `mimeType.split('/')[1]` is wrong for the model types —
88
+ * it yields "gltf-binary" — and the job board keys off the extension when a manifest
89
+ * omits `type`, so a GLB must land as `.glb`.
90
+ */
91
+ const EXTENSION_BY_MIME: Record<string, string> = {
92
+ 'model/gltf-binary': 'glb',
93
+ 'model/gltf+json': 'gltf',
94
+ 'application/pdf': 'pdf',
95
+ 'image/jpeg': 'jpg',
96
+ 'image/png': 'png',
97
+ 'image/webp': 'webp',
98
+ 'image/gif': 'gif',
99
+ 'image/svg+xml': 'svg',
100
+ 'audio/mpeg': 'mp3',
101
+ 'audio/wav': 'wav',
102
+ 'video/mp4': 'mp4',
103
+ 'video/webm': 'webm',
104
+ };
105
+
106
+ function isGenericBinaryType(mimeType: string | undefined): boolean {
107
+ return GENERIC_BINARY_TYPES.includes((mimeType || '').split(';')[0].trim().toLowerCase());
108
+ }
109
+
110
+ /** A 3D deliverable, whether declared by content_type or implied by the source URL. */
111
+ function isModelDeliverable(contentType: string, sourceUrl?: string): boolean {
112
+ if (MODEL_CONTENT_TYPES.includes(contentType)) return true;
113
+ return Boolean(sourceUrl && MODEL_EXT_RE.test(sourceUrl.split('?')[0]));
114
+ }
115
+
116
+ function modelMimeFor(contentType: string, sourceUrl?: string): string {
117
+ if (MODEL_CONTENT_TYPES.includes(contentType)) return contentType;
118
+ return /\.gltf(?:$|[?#])/i.test((sourceUrl || '').split('?')[0]) ? 'model/gltf+json' : 'model/gltf-binary';
119
+ }
120
+
121
+ function extensionFor(mimeType: string, sourceUrl?: string, filename?: string): string {
122
+ if (filename && filename.includes('.')) return filename.split('.').pop()!.toLowerCase();
123
+ const mapped = EXTENSION_BY_MIME[mimeType];
124
+ if (mapped) return mapped;
125
+ const path = (sourceUrl || '').split('?')[0].split('#')[0];
126
+ const fromUrl = path.includes('.') ? path.split('.').pop()! : '';
127
+ if (fromUrl && fromUrl.length <= 5 && !fromUrl.includes('/')) return fromUrl.toLowerCase();
128
+ return mimeType.split('/')[1]?.split('+')[0] || 'bin';
129
+ }
130
+
82
131
  const MAX_DOWNLOAD_SIZE = 50 * 1024 * 1024;
83
132
  async function downloadFromUrl(url: string): Promise<{ buffer: Buffer; mimeType: string } | null> {
84
133
  if (!/^https?:\/\//.test(url)) return null;
@@ -387,6 +436,9 @@ export default function creativeSkill(api: SkillApi): void {
387
436
  ' Images referenced as ![alt](url) in the Markdown are downloaded and embedded in the PDF.',
388
437
  ' Do NOT include <cite> or other HTML tags in the content — use clean Markdown only.',
389
438
  ' image/*, audio/*, video/* — downloads source_url and uploads binary to IPFS',
439
+ ' model/gltf-binary (.glb), model/gltf+json (.gltf) — downloads source_url and uploads the 3D',
440
+ ' model to IPFS. The job board renders it in an interactive three.js viewer.',
441
+ ' A source_url ending .glb/.gltf is treated as a model even with no content_type.',
390
442
  ' text/csv, text/plain, text/html, application/json — uploads the text as a file on IPFS (the URL serves the raw file)',
391
443
  'Do NOT store a delivery manifest with this tool: pass the manifest JSON string itself as evidence_uri to xpr_deliver_job.',
392
444
  ].join('\n'),
@@ -397,8 +449,8 @@ export default function creativeSkill(api: SkillApi): void {
397
449
  job_id: { type: 'number', description: 'Job ID' },
398
450
  content: { type: 'string', description: 'Full deliverable content (markdown, text, CSV, etc.). For media types, can be empty if source_url is provided.' },
399
451
  content_type: { type: 'string', description: 'MIME type: text/markdown (default), application/pdf, image/png, audio/mpeg, video/mp4, text/csv, etc.' },
400
- source_url: { type: 'string', description: 'URL to download binary content from (for image/audio/video). The file is downloaded and uploaded to IPFS.' },
401
- filename: { type: 'string', description: 'Optional filename for the deliverable (e.g. "report.pdf")' },
452
+ source_url: { type: 'string', description: 'URL to download binary content from (for image/audio/video/3D model). The file is downloaded and uploaded to IPFS.' },
453
+ filename: { type: 'string', description: 'Optional filename for the deliverable (e.g. "report.pdf", "scene.glb"). The extension matters — it is how the job board identifies the file when a manifest omits its type.' },
402
454
  },
403
455
  },
404
456
  handler: async ({ job_id, content, content_type, source_url, filename }: {
@@ -432,21 +484,31 @@ export default function creativeSkill(api: SkillApi): void {
432
484
  }
433
485
  }
434
486
 
435
- if (ct.startsWith('image/') || ct.startsWith('audio/') || ct.startsWith('video/') || ct === 'application/octet-stream') {
487
+ const isModel = isModelDeliverable(ct, source_url);
488
+
489
+ if (isModel || ct.startsWith('image/') || ct.startsWith('audio/') || ct.startsWith('video/') || ct === 'application/octet-stream') {
436
490
  let buffer: Buffer | null = null;
437
491
  let mimeType = ct;
438
492
 
439
493
  if (source_url) {
440
494
  const downloaded = await downloadFromUrl(source_url);
441
- if (downloaded) { buffer = downloaded.buffer; mimeType = downloaded.mimeType || ct; }
495
+ if (downloaded) {
496
+ buffer = downloaded.buffer;
497
+ // Model hosts routinely serve GLBs as application/octet-stream, so a generic
498
+ // response type must not overwrite the specific type we already worked out.
499
+ if (isModel) mimeType = modelMimeFor(ct, source_url);
500
+ else if (!isGenericBinaryType(downloaded.mimeType)) mimeType = downloaded.mimeType;
501
+ else mimeType = ct;
502
+ }
442
503
  } else if (content) {
443
504
  buffer = Buffer.from(content, 'base64');
505
+ if (isModel) mimeType = modelMimeFor(ct, source_url);
444
506
  }
445
507
 
446
508
  if (!buffer) return { stored: false, error: 'Failed to obtain binary content. Provide source_url for media types.' };
447
509
 
448
510
  setDeliverable(job_id, { content: source_url || '[binary]', content_type: mimeType, created_at: ts });
449
- const ext = mimeType.split('/')[1]?.split('+')[0] || 'bin';
511
+ const ext = extensionFor(mimeType, source_url, filename);
450
512
  const url = await uploadBinaryToIpfs(buffer, filename || `job-${job_id}.${ext}`, mimeType);
451
513
  if (url) {
452
514
  console.log(`[deliverable] Job ${job_id} ${mimeType} → IPFS: ${url}`);
@@ -21,6 +21,7 @@ You are an autonomous AI agent operating on XPR Network's trustless agent regist
21
21
  - Monitor your trust score breakdown: KYC (0-30) + Stake (0-20) + Reputation (0-40) + Longevity (0-10) = max 100
22
22
  - Use `xpr_get_trust_score` to check your current standing
23
23
  - Use `xpr_update_agent` to update profile fields
24
+ - **If your operator tells you to stop or retire:** there is no unregister. Call `xpr_set_agent_status` with `active: false` so nobody can hire you, bid for you or buy your listings while you are down; your history and reviews stay on record. Finish or deliver any job already in progress if you can. Tell the operator which jobs you cannot finish — refunding those is their call (`agentcancel`, signed by hand), not yours. Coming back is the same tool with `active: true`.
24
25
 
25
26
  ### 2. Job Lifecycle
26
27
  Jobs follow this state machine:
@@ -1,89 +0,0 @@
1
- "use strict";
2
- /**
3
- * CLI-backed session factories.
4
- *
5
- * Provides two shapes from the same underlying proton CLI wrapper:
6
- *
7
- * 1. createCliSession() → ProtonSession (SDK shape)
8
- * Used by openclaw/src/session.ts and downstream tools/registries.
9
- * Preserves the SDK's public ProtonSession interface — no changes to
10
- * sdk/src/types.ts, no breaking changes for SDK consumers.
11
- *
12
- * 2. createCliApi() → eosjs-Api lookalike + auth metadata
13
- * Used by skill files (defi, nft, lending, governance, xmd) that
14
- * previously called `await session.api.transact({actions}, options)`.
15
- * The .transact() signature matches eosjs so handler bodies need no
16
- * changes — only the session factory swaps.
17
- *
18
- * Both shapes route every signed action through `proton transaction:push`.
19
- * Neither holds, reads, or transmits private key material.
20
- */
21
- Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.createCliSession = createCliSession;
23
- exports.createCliApi = createCliApi;
24
- const js_1 = require("@proton/js");
25
- const proton_cli_1 = require("./proton-cli");
26
- const DEFAULT_PERMISSION = 'active';
27
- /**
28
- * Result of CLI signing, normalised to the SDK's TransactionResult shape.
29
- * `processed` is best-effort: proton CLI returns the full Hyperion-style
30
- * trace, but we only surface block_num and block_time for SDK compatibility.
31
- */
32
- function normaliseResult(result) {
33
- const processed = result.processed;
34
- return {
35
- transaction_id: result.transaction_id,
36
- processed: {
37
- block_num: processed?.block_num ?? processed?.receipt?.block_num ?? 0,
38
- block_time: processed?.block_time ?? '',
39
- },
40
- };
41
- }
42
- function toCliActions(actions) {
43
- return actions.map((a) => ({
44
- account: a.account,
45
- name: a.name,
46
- authorization: a.authorization,
47
- data: a.data,
48
- }));
49
- }
50
- /**
51
- * Create a ProtonSession (SDK shape) backed by the proton CLI.
52
- * No private key required — the CLI signs internally via its keychain.
53
- */
54
- function createCliSession(opts) {
55
- const account = opts.account;
56
- const permission = opts.permission ?? DEFAULT_PERMISSION;
57
- const rpcEndpoint = opts.rpcEndpoint ?? 'https://proton.greymass.com';
58
- const rpc = new js_1.JsonRpc(rpcEndpoint);
59
- const session = {
60
- auth: { actor: account, permission },
61
- link: {
62
- transact: async (args) => {
63
- const result = await (0, proton_cli_1.execTransactionPush)({ actions: toCliActions(args.actions) });
64
- return normaliseResult(result);
65
- },
66
- },
67
- };
68
- return { rpc, session };
69
- }
70
- /**
71
- * Create an eosjs-Api lookalike backed by the proton CLI.
72
- * Drop-in replacement for the `api` returned by skill `getSession()`
73
- * functions that used to construct `new Api({ rpc, signatureProvider })`.
74
- *
75
- * The blocksBehind/expireSeconds options are accepted but ignored —
76
- * proton CLI manages tx headers internally. Skill code remains unchanged.
77
- */
78
- function createCliApi(opts) {
79
- const account = opts.account;
80
- const permission = opts.permission ?? DEFAULT_PERMISSION;
81
- const api = {
82
- transact: async (tx, _options) => {
83
- const result = await (0, proton_cli_1.execTransactionPush)({ actions: toCliActions(tx.actions) });
84
- return normaliseResult(result);
85
- },
86
- };
87
- return { api, account, permission };
88
- }
89
- //# sourceMappingURL=cli-session.js.map
@@ -1,60 +0,0 @@
1
- /**
2
- * CLI-backed session factories.
3
- *
4
- * Provides two shapes from the same underlying proton CLI wrapper:
5
- *
6
- * 1. createCliSession() → ProtonSession (SDK shape)
7
- * Used by openclaw/src/session.ts and downstream tools/registries.
8
- * Preserves the SDK's public ProtonSession interface — no changes to
9
- * sdk/src/types.ts, no breaking changes for SDK consumers.
10
- *
11
- * 2. createCliApi() → eosjs-Api lookalike + auth metadata
12
- * Used by skill files (defi, nft, lending, governance, xmd) that
13
- * previously called `await session.api.transact({actions}, options)`.
14
- * The .transact() signature matches eosjs so handler bodies need no
15
- * changes — only the session factory swaps.
16
- *
17
- * Both shapes route every signed action through `proton transaction:push`.
18
- * Neither holds, reads, or transmits private key material.
19
- */
20
- import { JsonRpc } from '@proton/js';
21
- import type { ProtonSession, TransactArgs, TransactionResult } from '@xpr-agents/sdk';
22
- export interface CliSessionOptions {
23
- account: string;
24
- permission?: string;
25
- rpcEndpoint?: string;
26
- }
27
- /**
28
- * Create a ProtonSession (SDK shape) backed by the proton CLI.
29
- * No private key required — the CLI signs internally via its keychain.
30
- */
31
- export declare function createCliSession(opts: CliSessionOptions): {
32
- rpc: JsonRpc;
33
- session: ProtonSession;
34
- };
35
- /**
36
- * Lightweight Api lookalike returned by createCliApi(). Matches the subset
37
- * of eosjs Api that the 5 signing skills use.
38
- */
39
- export interface CliApi {
40
- transact(tx: {
41
- actions: TransactArgs['actions'];
42
- }, options?: {
43
- blocksBehind?: number;
44
- expireSeconds?: number;
45
- }): Promise<TransactionResult>;
46
- }
47
- /**
48
- * Create an eosjs-Api lookalike backed by the proton CLI.
49
- * Drop-in replacement for the `api` returned by skill `getSession()`
50
- * functions that used to construct `new Api({ rpc, signatureProvider })`.
51
- *
52
- * The blocksBehind/expireSeconds options are accepted but ignored —
53
- * proton CLI manages tx headers internally. Skill code remains unchanged.
54
- */
55
- export declare function createCliApi(opts: CliSessionOptions): {
56
- api: CliApi;
57
- account: string;
58
- permission: string;
59
- };
60
- //# sourceMappingURL=cli-session.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-session.d.ts","sourceRoot":"","sources":["../src/cli-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAKtF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA6BD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG;IACzD,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,aAAa,CAAC;CACxB,CAkBA;AAED;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,CACN,EAAE,EAAE;QAAE,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,CAAA;KAAE,EACxC,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAC1D,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,iBAAiB,GAAG;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAYA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-session.js","sourceRoot":"","sources":["../src/cli-session.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;AA6CH,4CAqBC;AAqBD,oCAgBC;AArGD,mCAAqC;AAErC,6CAAmE;AAEnE,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAQpC;;;;GAIG;AACH,SAAS,eAAe,CAAC,MAAuD;IAC9E,MAAM,SAAS,GAAG,MAAM,CAAC,SAEZ,CAAC;IACd,OAAO;QACL,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,SAAS,EAAE;YACT,SAAS,EAAE,SAAS,EAAE,SAAS,IAAI,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,CAAC;YACrE,UAAU,EAAE,SAAS,EAAE,UAAU,IAAI,EAAE;SACxC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,OAAgC;IACpD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,IAAI,EAAE,CAAC,CAAC,IAAI;KACb,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,IAAuB;IAItD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,kBAAkB,CAAC;IACzD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,6BAA6B,CAAC;IAEtE,MAAM,GAAG,GAAG,IAAI,YAAO,CAAC,WAAW,CAAC,CAAC;IAErC,MAAM,OAAO,GAAkB;QAC7B,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE;QACpC,IAAI,EAAE;YACJ,QAAQ,EAAE,KAAK,EAAE,IAAkB,EAA8B,EAAE;gBACjE,MAAM,MAAM,GAAG,MAAM,IAAA,gCAAmB,EAAC,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAClF,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC;YACjC,CAAC;SACF;KACF,CAAC;IAEF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC;AAaD;;;;;;;GAOG;AACH,SAAgB,YAAY,CAAC,IAAuB;IAKlD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,kBAAkB,CAAC;IAEzD,MAAM,GAAG,GAAW;QAClB,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE;YAC/B,MAAM,MAAM,GAAG,MAAM,IAAA,gCAAmB,EAAC,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAChF,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;KACF,CAAC;IAEF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACtC,CAAC"}
package/dist/index 2.js DELETED
@@ -1,125 +0,0 @@
1
- "use strict";
2
- /**
3
- * XPR Agents OpenClaw Plugin
4
- *
5
- * Registers 83 tools for interacting with the XPR Network Trustless Agent Registry:
6
- * - 11 Agent Core tools (registration, profile, plugins, trust scores, ownership)
7
- * - 7 Feedback tools (ratings, disputes, scores)
8
- * - 9 Validation tools (validators, validations, challenges)
9
- * - 32 Escrow tools (jobs, milestones, disputes, arbitration, bidding, services)
10
- * - 4 Indexer tools (search, events, stats, health)
11
- * - 5 A2A tools (discover, message, task status, cancel, delegate)
12
- * - 15 Shellbook tools (posts, comments, voting, subshells, search, profiles)
13
- */
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.ProtonCliError = exports.checkKeychainPopulated = exports.checkProtonCli = exports.getTableRows = exports.execTransactionPush = exports.execAction = exports.createCliApi = exports.createCliSession = void 0;
16
- exports.default = xprAgentsPlugin;
17
- const session_1 = require("./session");
18
- const agent_1 = require("./tools/agent");
19
- const feedback_1 = require("./tools/feedback");
20
- const validation_1 = require("./tools/validation");
21
- const escrow_1 = require("./tools/escrow");
22
- const indexer_1 = require("./tools/indexer");
23
- const a2a_1 = require("./tools/a2a");
24
- const shellbook_1 = require("./tools/shellbook");
25
- // Re-export CLI session factories. Used by skill packages to obtain a
26
- // signing session backed by the proton CLI (no private key in process).
27
- var cli_session_1 = require("./cli-session");
28
- Object.defineProperty(exports, "createCliSession", { enumerable: true, get: function () { return cli_session_1.createCliSession; } });
29
- Object.defineProperty(exports, "createCliApi", { enumerable: true, get: function () { return cli_session_1.createCliApi; } });
30
- var proton_cli_1 = require("./proton-cli");
31
- Object.defineProperty(exports, "execAction", { enumerable: true, get: function () { return proton_cli_1.execAction; } });
32
- Object.defineProperty(exports, "execTransactionPush", { enumerable: true, get: function () { return proton_cli_1.execTransactionPush; } });
33
- Object.defineProperty(exports, "getTableRows", { enumerable: true, get: function () { return proton_cli_1.getTableRows; } });
34
- Object.defineProperty(exports, "checkProtonCli", { enumerable: true, get: function () { return proton_cli_1.checkProtonCli; } });
35
- Object.defineProperty(exports, "checkKeychainPopulated", { enumerable: true, get: function () { return proton_cli_1.checkKeychainPopulated; } });
36
- Object.defineProperty(exports, "ProtonCliError", { enumerable: true, get: function () { return proton_cli_1.ProtonCliError; } });
37
- /**
38
- * Create an adapter that bridges the real OpenClaw API to our internal PluginApi.
39
- * This lets all 57 tool registrations work unchanged.
40
- */
41
- function createAdapter(realApi) {
42
- return {
43
- registerTool(tool) {
44
- realApi.registerTool({
45
- name: tool.name,
46
- description: tool.description,
47
- parameters: tool.parameters,
48
- async execute(_id, params) {
49
- const result = await tool.handler(params);
50
- const text = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
51
- return { content: [{ type: 'text', text }] };
52
- },
53
- });
54
- },
55
- getConfig() {
56
- return realApi.pluginConfig || {};
57
- },
58
- };
59
- }
60
- function xprAgentsPlugin(realApi) {
61
- // Detect whether we're running inside the real OpenClaw runtime or in tests.
62
- // Real OpenClaw API has pluginConfig property; our test mock has getConfig method.
63
- const api = typeof realApi.getConfig === 'function'
64
- ? realApi
65
- : createAdapter(realApi);
66
- const rawConfig = api.getConfig();
67
- const network = rawConfig.network || 'mainnet';
68
- const defaultRpc = network === 'mainnet' ? 'https://proton.eosusa.io' : 'https://tn1.protonnz.com';
69
- const rpcEndpoint = rawConfig.rpcEndpoint || process.env.XPR_RPC_ENDPOINT || defaultRpc;
70
- // Signing is enabled when XPR_ACCOUNT is set. The proton CLI handles the
71
- // private key — the agent process never sees it. Verifying CLI presence
72
- // is the entry-point's job (starter/agent/src/index.ts), not the plugin's.
73
- const hasCredentials = !!process.env.XPR_ACCOUNT;
74
- // Create RPC connection and optional session
75
- let rpc;
76
- let session;
77
- if (hasCredentials) {
78
- const result = (0, session_1.createSession)({ rpcEndpoint });
79
- rpc = result.rpc;
80
- session = result.session;
81
- }
82
- else {
83
- rpc = (0, session_1.createReadOnlyRpc)(rpcEndpoint);
84
- }
85
- const contractsRaw = (rawConfig.contracts || {});
86
- const config = {
87
- rpc: rpc,
88
- session,
89
- network: rawConfig.network || 'mainnet',
90
- rpcEndpoint,
91
- indexerUrl: rawConfig.indexerUrl || process.env.INDEXER_URL || 'https://indexer.xpragents.com',
92
- contracts: {
93
- agentcore: contractsRaw.agentcore || 'agentcore',
94
- agentfeed: contractsRaw.agentfeed || 'agentfeed',
95
- agentvalid: contractsRaw.agentvalid || 'agentvalid',
96
- agentescrow: contractsRaw.agentescrow || 'agentescrow',
97
- },
98
- confirmHighRisk: rawConfig.confirmHighRisk !== false,
99
- maxTransferAmount: rawConfig.maxTransferAmount || 10000000,
100
- };
101
- // Register all tool groups. Wrap registerTool with a counter so the boot
102
- // log can report the actual count — operators grep for this line to
103
- // confirm the plugin loaded fully, and a count that drifts from the docs
104
- // makes that signal worthless.
105
- let toolCount = 0;
106
- const countingApi = {
107
- ...api,
108
- registerTool: (tool) => {
109
- toolCount++;
110
- return api.registerTool(tool);
111
- },
112
- };
113
- (0, agent_1.registerAgentTools)(countingApi, config);
114
- (0, feedback_1.registerFeedbackTools)(countingApi, config);
115
- (0, validation_1.registerValidationTools)(countingApi, config);
116
- (0, escrow_1.registerEscrowTools)(countingApi, config);
117
- (0, indexer_1.registerIndexerTools)(countingApi, config);
118
- (0, a2a_1.registerA2ATools)(countingApi, config);
119
- (0, shellbook_1.registerShellbookTools)(countingApi);
120
- if (!hasCredentials) {
121
- console.log('[xpr-agents] Read-only mode: XPR_ACCOUNT not set. Write tools will fail.');
122
- }
123
- console.log(`[xpr-agents] Plugin loaded: ${toolCount} tools, ${config.network} (${rpcEndpoint})`);
124
- }
125
- //# sourceMappingURL=index.js.map
@@ -1,43 +0,0 @@
1
- /**
2
- * XPR Agents OpenClaw Plugin
3
- *
4
- * Registers 83 tools for interacting with the XPR Network Trustless Agent Registry:
5
- * - 11 Agent Core tools (registration, profile, plugins, trust scores, ownership)
6
- * - 7 Feedback tools (ratings, disputes, scores)
7
- * - 9 Validation tools (validators, validations, challenges)
8
- * - 32 Escrow tools (jobs, milestones, disputes, arbitration, bidding, services)
9
- * - 4 Indexer tools (search, events, stats, health)
10
- * - 5 A2A tools (discover, message, task status, cancel, delegate)
11
- * - 15 Shellbook tools (posts, comments, voting, subshells, search, profiles)
12
- */
13
- import type { PluginApi } from './types';
14
- export type { SkillManifest, SkillApi, LoadedSkill } from './skill-types';
15
- export type { ToolDefinition, PluginApi } from './types';
16
- export { createCliSession, createCliApi } from './cli-session';
17
- export type { CliSessionOptions, CliApi } from './cli-session';
18
- export { execAction, execTransactionPush, getTableRows, checkProtonCli, checkKeychainPopulated, ProtonCliError, } from './proton-cli';
19
- export type { CliErrorCode, CliAction, CliTransactionResult, TableQueryOpts } from './proton-cli';
20
- /**
21
- * OpenClaw plugin API shape (real runtime API).
22
- * Plugins receive this from the OpenClaw gateway.
23
- */
24
- interface OpenClawPluginApi {
25
- id: string;
26
- name: string;
27
- config?: Record<string, unknown>;
28
- pluginConfig?: Record<string, unknown>;
29
- registerTool(tool: {
30
- name: string;
31
- description: string;
32
- parameters: unknown;
33
- execute: (id: string, params: Record<string, unknown>) => Promise<{
34
- content: Array<{
35
- type: string;
36
- text?: string;
37
- }>;
38
- }>;
39
- }, opts?: unknown): void;
40
- [key: string]: unknown;
41
- }
42
- export default function xprAgentsPlugin(realApi: OpenClawPluginApi | PluginApi): void;
43
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,OAAO,KAAK,EAAE,SAAS,EAAgC,MAAM,SAAS,CAAC;AAGvE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC1E,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAIzD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAElG;;;GAGG;AACH,UAAU,iBAAiB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,YAAY,CAAC,IAAI,EAAE;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,OAAO,CAAC;QACpB,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;YAChE,OAAO,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,IAAI,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC,CAAC;SACjD,CAAC,CAAC;KACJ,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AA0BD,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,GAAG,IAAI,CAyEpF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}