@troykelly/openclaw-projects 0.0.30 → 0.0.31
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/register-openclaw.d.ts.map +1 -1
- package/dist/register-openclaw.js +224 -3
- package/dist/register-openclaw.js.map +1 -1
- package/dist/services/api-source-service.d.ts +181 -0
- package/dist/services/api-source-service.d.ts.map +1 -0
- package/dist/services/api-source-service.js +120 -0
- package/dist/services/api-source-service.js.map +1 -0
- package/dist/tools/api-credential-manage.d.ts +83 -0
- package/dist/tools/api-credential-manage.d.ts.map +1 -0
- package/dist/tools/api-credential-manage.js +71 -0
- package/dist/tools/api-credential-manage.js.map +1 -0
- package/dist/tools/api-get.d.ts +47 -0
- package/dist/tools/api-get.d.ts.map +1 -0
- package/dist/tools/api-get.js +41 -0
- package/dist/tools/api-get.js.map +1 -0
- package/dist/tools/api-list.d.ts +54 -0
- package/dist/tools/api-list.d.ts.map +1 -0
- package/dist/tools/api-list.js +46 -0
- package/dist/tools/api-list.js.map +1 -0
- package/dist/tools/api-onboard.d.ts +134 -0
- package/dist/tools/api-onboard.d.ts.map +1 -0
- package/dist/tools/api-onboard.js +109 -0
- package/dist/tools/api-onboard.js.map +1 -0
- package/dist/tools/api-recall.d.ts +69 -0
- package/dist/tools/api-recall.d.ts.map +1 -0
- package/dist/tools/api-recall.js +101 -0
- package/dist/tools/api-recall.js.map +1 -0
- package/dist/tools/api-refresh.d.ts +50 -0
- package/dist/tools/api-refresh.d.ts.map +1 -0
- package/dist/tools/api-refresh.js +55 -0
- package/dist/tools/api-refresh.js.map +1 -0
- package/dist/tools/api-remove.d.ts +46 -0
- package/dist/tools/api-remove.d.ts.map +1 -0
- package/dist/tools/api-remove.js +45 -0
- package/dist/tools/api-remove.js.map +1 -0
- package/dist/tools/api-restore.d.ts +45 -0
- package/dist/tools/api-restore.d.ts.map +1 -0
- package/dist/tools/api-restore.js +41 -0
- package/dist/tools/api-restore.js.map +1 -0
- package/dist/tools/api-update.d.ts +57 -0
- package/dist/tools/api-update.d.ts.map +1 -0
- package/dist/tools/api-update.js +46 -0
- package/dist/tools/api-update.js.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +10 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/types/openclaw-api.d.ts +1 -0
- package/dist/types/openclaw-api.d.ts.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-openclaw.d.ts","sourceRoot":"","sources":["../src/register-openclaw.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,KAAK,YAAY,EAA2G,MAAM,aAAa,CAAC;AAKzJ,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"register-openclaw.d.ts","sourceRoot":"","sources":["../src/register-openclaw.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,KAAK,YAAY,EAA2G,MAAM,aAAa,CAAC;AAKzJ,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAyBxD,OAAO,KAAK,EAEV,UAAU,EAQV,iBAAiB,EAGlB,MAAM,yBAAyB,CAAC;AAajC,8CAA8C;AAC9C,UAAU,WAAW;IACnB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,uGAAuG;IACvG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4GAA4G;IAC5G,iBAAiB,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACzD,oEAAoE;IACpE,eAAe,EAAE,OAAO,CAAC;IACzB,mEAAmE;IACnE,sBAAsB,EAAE,MAAM,CAAC;IAC/B,2DAA2D;IAC3D,eAAe,EAAE,OAAO,CAAC;IACzB,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAyjDD;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA6C9E;AAwuED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAq9B9B,CAAC;AAEF,yDAAyD;AACzD,eAAe,gBAAgB,CAAC;AAEhC,2CAA2C;AAC3C,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCnB,CAAC"}
|
|
@@ -16,7 +16,7 @@ import { createGatewayMethods, registerGatewayRpcMethods } from './gateway/rpc-m
|
|
|
16
16
|
import { createAutoCaptureHook, createGraphAwareRecallHook } from './hooks.js';
|
|
17
17
|
import { createLogger } from './logger.js';
|
|
18
18
|
import { createNotificationService } from './services/notification-service.js';
|
|
19
|
-
import { createContextSearchTool, createLinksQueryTool, createLinksRemoveTool, createLinksSetTool, createProjectSearchTool, createSkillStoreAggregateTool, createSkillStoreCollectionsTool, createSkillStoreDeleteTool, createSkillStoreGetTool, createSkillStoreListTool, createSkillStorePutTool, createSkillStoreSearchTool, } from './tools/index.js';
|
|
19
|
+
import { createContextSearchTool, createLinksQueryTool, createLinksRemoveTool, createLinksSetTool, createProjectSearchTool, createSkillStoreAggregateTool, createSkillStoreCollectionsTool, createSkillStoreDeleteTool, createSkillStoreGetTool, createSkillStoreListTool, createSkillStorePutTool, createSkillStoreSearchTool, createApiOnboardTool, createApiRecallTool, createApiGetTool, createApiListTool, createApiUpdateTool, createApiCredentialManageTool, createApiRefreshTool, createApiRemoveTool, createApiRestoreTool, } from './tools/index.js';
|
|
20
20
|
import { autoLinkInboundMessage } from './utils/auto-linker.js';
|
|
21
21
|
import { blendScores, computeGeoScore, haversineDistanceKm } from './utils/geo.js';
|
|
22
22
|
import { createBoundaryMarkers, detectInjectionPatternsAsync, sanitizeMessageForContext, sanitizeMetadataField, wrapExternalMessage, } from './utils/injection-protection.js';
|
|
@@ -1439,6 +1439,107 @@ const namespaceRevokeSchema = {
|
|
|
1439
1439
|
},
|
|
1440
1440
|
required: ['namespace', 'grant_id'],
|
|
1441
1441
|
};
|
|
1442
|
+
// ── API Onboarding tool schemas (#1784, #1785, #1786) ─────────────────────
|
|
1443
|
+
const apiOnboardSchema = {
|
|
1444
|
+
type: 'object',
|
|
1445
|
+
properties: {
|
|
1446
|
+
spec_url: { type: 'string', description: 'URL to fetch the OpenAPI spec from.', format: 'uri' },
|
|
1447
|
+
spec_content: { type: 'string', description: 'Inline OpenAPI spec content (JSON or YAML).' },
|
|
1448
|
+
name: { type: 'string', description: 'Human-readable name for the API.', maxLength: 200 },
|
|
1449
|
+
description: { type: 'string', description: 'Description of the API.', maxLength: 2000 },
|
|
1450
|
+
tags: { type: 'array', description: 'Tags to categorise the API.', items: { type: 'string' } },
|
|
1451
|
+
credentials: {
|
|
1452
|
+
type: 'array',
|
|
1453
|
+
description: 'Credentials for authenticating API calls.',
|
|
1454
|
+
items: {
|
|
1455
|
+
type: 'object',
|
|
1456
|
+
properties: {
|
|
1457
|
+
header_name: { type: 'string' },
|
|
1458
|
+
header_prefix: { type: 'string' },
|
|
1459
|
+
resolve_strategy: { type: 'string', enum: ['literal', 'env', 'file', 'command'] },
|
|
1460
|
+
resolve_reference: { type: 'string' },
|
|
1461
|
+
purpose: { type: 'string', enum: ['api_call', 'spec_fetch'] },
|
|
1462
|
+
},
|
|
1463
|
+
required: ['header_name', 'resolve_strategy', 'resolve_reference'],
|
|
1464
|
+
},
|
|
1465
|
+
},
|
|
1466
|
+
spec_auth_headers: { type: 'object', description: 'Headers for fetching the spec URL (if auth-protected).', additionalProperties: { type: 'string' } },
|
|
1467
|
+
},
|
|
1468
|
+
required: [],
|
|
1469
|
+
};
|
|
1470
|
+
const apiRecallSchema = {
|
|
1471
|
+
type: 'object',
|
|
1472
|
+
properties: {
|
|
1473
|
+
query: { type: 'string', description: 'Natural-language search query for API capabilities.', minLength: 1, maxLength: 1000 },
|
|
1474
|
+
limit: { type: 'integer', description: 'Maximum results to return.', minimum: 1, maximum: 50, default: 10 },
|
|
1475
|
+
memory_kind: { type: 'string', description: 'Filter by memory kind.', enum: ['overview', 'tag_group', 'operation'] },
|
|
1476
|
+
api_source_id: { type: 'string', description: 'Filter to a specific API source.', format: 'uuid' },
|
|
1477
|
+
tags: { type: 'array', description: 'Filter by tags.', items: { type: 'string' } },
|
|
1478
|
+
},
|
|
1479
|
+
required: ['query'],
|
|
1480
|
+
};
|
|
1481
|
+
const apiGetSchema = {
|
|
1482
|
+
type: 'object',
|
|
1483
|
+
properties: {
|
|
1484
|
+
id: { type: 'string', description: 'UUID of the API source.', format: 'uuid' },
|
|
1485
|
+
},
|
|
1486
|
+
required: ['id'],
|
|
1487
|
+
};
|
|
1488
|
+
const apiListSchema = {
|
|
1489
|
+
type: 'object',
|
|
1490
|
+
properties: {
|
|
1491
|
+
limit: { type: 'integer', description: 'Maximum results.', minimum: 1, maximum: 100 },
|
|
1492
|
+
offset: { type: 'integer', description: 'Pagination offset.', minimum: 0 },
|
|
1493
|
+
status: { type: 'string', description: 'Filter by status.', enum: ['active', 'error', 'disabled'] },
|
|
1494
|
+
},
|
|
1495
|
+
required: [],
|
|
1496
|
+
};
|
|
1497
|
+
const apiUpdateSchema = {
|
|
1498
|
+
type: 'object',
|
|
1499
|
+
properties: {
|
|
1500
|
+
id: { type: 'string', description: 'UUID of the API source to update.', format: 'uuid' },
|
|
1501
|
+
name: { type: 'string', description: 'New name.', maxLength: 200 },
|
|
1502
|
+
description: { type: 'string', description: 'New description.', maxLength: 2000 },
|
|
1503
|
+
tags: { type: 'array', description: 'New tags.', items: { type: 'string' } },
|
|
1504
|
+
status: { type: 'string', description: 'New status.', enum: ['active', 'error', 'disabled'] },
|
|
1505
|
+
},
|
|
1506
|
+
required: ['id'],
|
|
1507
|
+
};
|
|
1508
|
+
const apiCredentialManageSchema = {
|
|
1509
|
+
type: 'object',
|
|
1510
|
+
properties: {
|
|
1511
|
+
api_source_id: { type: 'string', description: 'UUID of the API source.', format: 'uuid' },
|
|
1512
|
+
action: { type: 'string', description: 'Action to perform.', enum: ['add', 'update', 'remove'] },
|
|
1513
|
+
credential_id: { type: 'string', description: 'UUID of the credential (for update/remove).', format: 'uuid' },
|
|
1514
|
+
header_name: { type: 'string', description: 'HTTP header name (e.g. Authorization).' },
|
|
1515
|
+
header_prefix: { type: 'string', description: 'Header value prefix (e.g. Bearer).' },
|
|
1516
|
+
resolve_strategy: { type: 'string', description: 'How to resolve the credential.', enum: ['literal', 'env', 'file', 'command'] },
|
|
1517
|
+
resolve_reference: { type: 'string', description: 'Credential value or reference.' },
|
|
1518
|
+
purpose: { type: 'string', description: 'Credential purpose.', enum: ['api_call', 'spec_fetch'] },
|
|
1519
|
+
},
|
|
1520
|
+
required: ['api_source_id', 'action'],
|
|
1521
|
+
};
|
|
1522
|
+
const apiRefreshSchema = {
|
|
1523
|
+
type: 'object',
|
|
1524
|
+
properties: {
|
|
1525
|
+
id: { type: 'string', description: 'UUID of the API source to refresh.', format: 'uuid' },
|
|
1526
|
+
},
|
|
1527
|
+
required: ['id'],
|
|
1528
|
+
};
|
|
1529
|
+
const apiRemoveSchema = {
|
|
1530
|
+
type: 'object',
|
|
1531
|
+
properties: {
|
|
1532
|
+
id: { type: 'string', description: 'UUID of the API source to soft-delete.', format: 'uuid' },
|
|
1533
|
+
},
|
|
1534
|
+
required: ['id'],
|
|
1535
|
+
};
|
|
1536
|
+
const apiRestoreSchema = {
|
|
1537
|
+
type: 'object',
|
|
1538
|
+
properties: {
|
|
1539
|
+
id: { type: 'string', description: 'UUID of the API source to restore.', format: 'uuid' },
|
|
1540
|
+
},
|
|
1541
|
+
required: ['id'],
|
|
1542
|
+
};
|
|
1442
1543
|
/**
|
|
1443
1544
|
* Async namespace discovery — fetches accessible namespaces from the API
|
|
1444
1545
|
* and updates state.resolvedNamespace.recall in-place (Issue #1537).
|
|
@@ -1490,10 +1591,11 @@ function createToolHandlers(state) {
|
|
|
1490
1591
|
const { config, logger, apiClient } = state;
|
|
1491
1592
|
// Issue #1644: Read user_id from mutable state on every call.
|
|
1492
1593
|
const getAgentId = () => state.agentId;
|
|
1493
|
-
/** Read user_id from mutable state on every call (Issue #1644) */
|
|
1594
|
+
/** Read user_id and namespace from mutable state on every call (Issue #1644, #1797) */
|
|
1494
1595
|
const reqOpts = () => ({
|
|
1495
1596
|
user_id: state.agentId,
|
|
1496
1597
|
user_email: state.agentEmail,
|
|
1598
|
+
namespace: state.resolvedNamespace.default,
|
|
1497
1599
|
});
|
|
1498
1600
|
/**
|
|
1499
1601
|
* Request options with namespace header for by-ID operations (#1760).
|
|
@@ -1694,7 +1796,7 @@ function createToolHandlers(state) {
|
|
|
1694
1796
|
};
|
|
1695
1797
|
}
|
|
1696
1798
|
// Multiple matches or low confidence → return candidates, don't delete
|
|
1697
|
-
const list = matches.map((m) => `- [${m.id
|
|
1799
|
+
const list = matches.map((m) => `- [${m.id}] ${m.content.slice(0, 60)}${m.content.length > 60 ? '...' : ''}`).join('\n');
|
|
1698
1800
|
return {
|
|
1699
1801
|
success: true,
|
|
1700
1802
|
data: {
|
|
@@ -3206,6 +3308,43 @@ function createToolHandlers(state) {
|
|
|
3206
3308
|
return { success: false, error: 'Failed to revoke namespace access' };
|
|
3207
3309
|
}
|
|
3208
3310
|
},
|
|
3311
|
+
// ── API Onboarding tools (#1784, #1785, #1786) ──────────────────────
|
|
3312
|
+
async api_onboard(params) {
|
|
3313
|
+
const tool = createApiOnboardTool({ client: apiClient, logger, config, user_id: getAgentId() });
|
|
3314
|
+
return tool.execute(params);
|
|
3315
|
+
},
|
|
3316
|
+
async api_recall(params) {
|
|
3317
|
+
const tool = createApiRecallTool({ client: apiClient, logger, config, user_id: getAgentId() });
|
|
3318
|
+
return tool.execute(params);
|
|
3319
|
+
},
|
|
3320
|
+
async api_get(params) {
|
|
3321
|
+
const tool = createApiGetTool({ client: apiClient, logger, config, user_id: getAgentId() });
|
|
3322
|
+
return tool.execute(params);
|
|
3323
|
+
},
|
|
3324
|
+
async api_list(params) {
|
|
3325
|
+
const tool = createApiListTool({ client: apiClient, logger, config, user_id: getAgentId() });
|
|
3326
|
+
return tool.execute(params);
|
|
3327
|
+
},
|
|
3328
|
+
async api_update(params) {
|
|
3329
|
+
const tool = createApiUpdateTool({ client: apiClient, logger, config, user_id: getAgentId() });
|
|
3330
|
+
return tool.execute(params);
|
|
3331
|
+
},
|
|
3332
|
+
async api_credential_manage(params) {
|
|
3333
|
+
const tool = createApiCredentialManageTool({ client: apiClient, logger, config, user_id: getAgentId() });
|
|
3334
|
+
return tool.execute(params);
|
|
3335
|
+
},
|
|
3336
|
+
async api_refresh(params) {
|
|
3337
|
+
const tool = createApiRefreshTool({ client: apiClient, logger, config, user_id: getAgentId() });
|
|
3338
|
+
return tool.execute(params);
|
|
3339
|
+
},
|
|
3340
|
+
async api_remove(params) {
|
|
3341
|
+
const tool = createApiRemoveTool({ client: apiClient, logger, config, user_id: getAgentId() });
|
|
3342
|
+
return tool.execute(params);
|
|
3343
|
+
},
|
|
3344
|
+
async api_restore(params) {
|
|
3345
|
+
const tool = createApiRestoreTool({ client: apiClient, logger, config, user_id: getAgentId() });
|
|
3346
|
+
return tool.execute(params);
|
|
3347
|
+
},
|
|
3209
3348
|
};
|
|
3210
3349
|
}
|
|
3211
3350
|
/**
|
|
@@ -3766,6 +3905,88 @@ export const registerOpenClaw = (api) => {
|
|
|
3766
3905
|
return toAgentToolResult(result);
|
|
3767
3906
|
},
|
|
3768
3907
|
},
|
|
3908
|
+
// ── API Onboarding tools (#1784, #1785, #1786) ──────────────────────
|
|
3909
|
+
{
|
|
3910
|
+
name: 'api_onboard',
|
|
3911
|
+
description: 'Onboard a new API by providing its OpenAPI spec URL or inline content. Parses the spec into searchable memories and optionally stores credentials.',
|
|
3912
|
+
parameters: withNamespace(apiOnboardSchema),
|
|
3913
|
+
execute: async (_toolCallId, params, _signal, _onUpdate) => {
|
|
3914
|
+
const result = await handlers.api_onboard(params);
|
|
3915
|
+
return toAgentToolResult(result);
|
|
3916
|
+
},
|
|
3917
|
+
},
|
|
3918
|
+
{
|
|
3919
|
+
name: 'api_recall',
|
|
3920
|
+
description: 'Search onboarded API memories to find endpoints, operations, and capabilities. Returns operation details including method, path, parameters, and credentials.',
|
|
3921
|
+
parameters: withNamespaces(apiRecallSchema),
|
|
3922
|
+
execute: async (_toolCallId, params, _signal, _onUpdate) => {
|
|
3923
|
+
const result = await handlers.api_recall(params);
|
|
3924
|
+
return toAgentToolResult(result);
|
|
3925
|
+
},
|
|
3926
|
+
},
|
|
3927
|
+
{
|
|
3928
|
+
name: 'api_get',
|
|
3929
|
+
description: 'Get details about a specific onboarded API source including its status, spec version, and tags.',
|
|
3930
|
+
parameters: apiGetSchema,
|
|
3931
|
+
execute: async (_toolCallId, params, _signal, _onUpdate) => {
|
|
3932
|
+
const result = await handlers.api_get(params);
|
|
3933
|
+
return toAgentToolResult(result);
|
|
3934
|
+
},
|
|
3935
|
+
},
|
|
3936
|
+
{
|
|
3937
|
+
name: 'api_list',
|
|
3938
|
+
description: 'List all onboarded API sources. Optionally filter by status (active, error, disabled).',
|
|
3939
|
+
parameters: apiListSchema,
|
|
3940
|
+
execute: async (_toolCallId, params, _signal, _onUpdate) => {
|
|
3941
|
+
const result = await handlers.api_list(params);
|
|
3942
|
+
return toAgentToolResult(result);
|
|
3943
|
+
},
|
|
3944
|
+
},
|
|
3945
|
+
{
|
|
3946
|
+
name: 'api_update',
|
|
3947
|
+
description: 'Update an onboarded API source. Change its name, description, tags, or status.',
|
|
3948
|
+
parameters: apiUpdateSchema,
|
|
3949
|
+
execute: async (_toolCallId, params, _signal, _onUpdate) => {
|
|
3950
|
+
const result = await handlers.api_update(params);
|
|
3951
|
+
return toAgentToolResult(result);
|
|
3952
|
+
},
|
|
3953
|
+
},
|
|
3954
|
+
{
|
|
3955
|
+
name: 'api_credential_manage',
|
|
3956
|
+
description: 'Manage credentials for an onboarded API source: add, update, or remove authentication headers.',
|
|
3957
|
+
parameters: apiCredentialManageSchema,
|
|
3958
|
+
execute: async (_toolCallId, params, _signal, _onUpdate) => {
|
|
3959
|
+
const result = await handlers.api_credential_manage(params);
|
|
3960
|
+
return toAgentToolResult(result);
|
|
3961
|
+
},
|
|
3962
|
+
},
|
|
3963
|
+
{
|
|
3964
|
+
name: 'api_refresh',
|
|
3965
|
+
description: 'Refresh an API source by re-fetching its OpenAPI spec and updating memories. Returns a diff summary.',
|
|
3966
|
+
parameters: apiRefreshSchema,
|
|
3967
|
+
execute: async (_toolCallId, params, _signal, _onUpdate) => {
|
|
3968
|
+
const result = await handlers.api_refresh(params);
|
|
3969
|
+
return toAgentToolResult(result);
|
|
3970
|
+
},
|
|
3971
|
+
},
|
|
3972
|
+
{
|
|
3973
|
+
name: 'api_remove',
|
|
3974
|
+
description: 'Soft-delete an onboarded API source. Can be restored later with api_restore.',
|
|
3975
|
+
parameters: apiRemoveSchema,
|
|
3976
|
+
execute: async (_toolCallId, params, _signal, _onUpdate) => {
|
|
3977
|
+
const result = await handlers.api_remove(params);
|
|
3978
|
+
return toAgentToolResult(result);
|
|
3979
|
+
},
|
|
3980
|
+
},
|
|
3981
|
+
{
|
|
3982
|
+
name: 'api_restore',
|
|
3983
|
+
description: 'Restore a previously soft-deleted API source.',
|
|
3984
|
+
parameters: apiRestoreSchema,
|
|
3985
|
+
execute: async (_toolCallId, params, _signal, _onUpdate) => {
|
|
3986
|
+
const result = await handlers.api_restore(params);
|
|
3987
|
+
return toAgentToolResult(result);
|
|
3988
|
+
},
|
|
3989
|
+
},
|
|
3769
3990
|
];
|
|
3770
3991
|
for (const tool of tools) {
|
|
3771
3992
|
api.registerTool(tool);
|