@realtimex/sdk 2.0.29 → 2.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/README.md +24 -0
- package/index.d.ts +82 -1
- package/index.js +250 -1
- package/package.json +1 -1
- package/skills/realtimex-moderator-sdk/SKILL.md +9 -5
package/README.md
CHANGED
|
@@ -19,5 +19,29 @@ const workspaces = await client.request("listWorkspaces");
|
|
|
19
19
|
`REALTIMEX_BASE_URL`. Desktop and `dev:all` runtimes propagate the resolved
|
|
20
20
|
dynamic `/cli` endpoint; the SDK does not guess a localhost port.
|
|
21
21
|
|
|
22
|
+
## Public webhook task delivery
|
|
23
|
+
|
|
24
|
+
Use a separate webhook client to trigger an existing public webhook endpoint.
|
|
25
|
+
Webhook endpoint creation and editing remain in RealtimeX settings.
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
const { createRealtimeXWebhookClient } = require("@realtimex/sdk");
|
|
29
|
+
|
|
30
|
+
const webhook = createRealtimeXWebhookClient({
|
|
31
|
+
endpointUrl: process.env.REALTIMEX_WEBHOOK_URL,
|
|
32
|
+
secret: process.env.REALTIMEX_WEBHOOK_SECRET,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const receipt = await webhook.trigger(
|
|
36
|
+
{ prompt: "Review this task", context: { sourceId: "task-123" } },
|
|
37
|
+
{ deliveryId: "task-123" }
|
|
38
|
+
);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The client signs the exact UTF-8 request bytes with HMAC-SHA256. Network and
|
|
42
|
+
server-error retries reuse the serialized body, timestamp, and delivery ID so
|
|
43
|
+
the receiving endpoint can deduplicate delivery safely. A successful receipt
|
|
44
|
+
confirms acceptance and routing, not agent-task completion.
|
|
45
|
+
|
|
22
46
|
The package also publishes generated skill assets under
|
|
23
47
|
`skills/realtimex-moderator-sdk`.
|
package/index.d.ts
CHANGED
|
@@ -423,6 +423,25 @@ export interface GetWorkspaceOptions extends RealtimeXRequestOptions {
|
|
|
423
423
|
body?: GetWorkspaceBody;
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
+
export type GoalKickoffComposerParams = Record<string, never>;
|
|
427
|
+
export type GoalKickoffComposerQuery = Record<string, never>;
|
|
428
|
+
export type GoalKickoffComposerHeaders = Record<string, never>;
|
|
429
|
+
export type GoalKickoffComposerBody = {
|
|
430
|
+
cdpUrl?: string;
|
|
431
|
+
mainAppUrl?: string;
|
|
432
|
+
artifactPath?: string;
|
|
433
|
+
screenshotDir?: string;
|
|
434
|
+
timeoutMs?: number;
|
|
435
|
+
confirmDestructive?: boolean;
|
|
436
|
+
};
|
|
437
|
+
export type GoalKickoffComposerResponse = Record<string, unknown>;
|
|
438
|
+
export interface GoalKickoffComposerOptions extends RealtimeXRequestOptions {
|
|
439
|
+
params?: GoalKickoffComposerParams;
|
|
440
|
+
query?: GoalKickoffComposerQuery;
|
|
441
|
+
headers?: GoalKickoffComposerHeaders & Record<string, string>;
|
|
442
|
+
body?: GoalKickoffComposerBody;
|
|
443
|
+
}
|
|
444
|
+
|
|
426
445
|
export type InstallPluginParams = Record<string, never>;
|
|
427
446
|
export type InstallPluginQuery = Record<string, never>;
|
|
428
447
|
export type InstallPluginHeaders = {
|
|
@@ -826,7 +845,7 @@ export type RespondTerminalIdlePromptHeaders = {
|
|
|
826
845
|
"x-app-id"?: string;
|
|
827
846
|
};
|
|
828
847
|
export type RespondTerminalIdlePromptBody = {
|
|
829
|
-
responseAction: "confirm-selected-option" | "cancel-prompt";
|
|
848
|
+
responseAction: "confirm-selected-option" | "confirm-persistent-workspace-trust" | "cancel-prompt";
|
|
830
849
|
expectedEventSeq: number;
|
|
831
850
|
dispatchKey: string;
|
|
832
851
|
};
|
|
@@ -1457,6 +1476,47 @@ export interface RealtimeXRequestOptions {
|
|
|
1457
1476
|
signal?: AbortSignal;
|
|
1458
1477
|
}
|
|
1459
1478
|
|
|
1479
|
+
export interface RealtimeXWebhookClientOptions {
|
|
1480
|
+
endpointUrl?: string;
|
|
1481
|
+
url?: string;
|
|
1482
|
+
secret?: string;
|
|
1483
|
+
signatureHeader?: string;
|
|
1484
|
+
signaturePrefix?: string;
|
|
1485
|
+
timestampHeader?: string;
|
|
1486
|
+
deliveryIdHeader?: string;
|
|
1487
|
+
eventTypeHeader?: string;
|
|
1488
|
+
sourceHeader?: string;
|
|
1489
|
+
eventType?: string;
|
|
1490
|
+
source?: string;
|
|
1491
|
+
headers?: Record<string, string>;
|
|
1492
|
+
maxRetries?: number;
|
|
1493
|
+
retryDelayMs?: number;
|
|
1494
|
+
timeoutMs?: number;
|
|
1495
|
+
fetch?: typeof fetch;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
export interface RealtimeXWebhookTriggerOptions {
|
|
1499
|
+
deliveryId?: string;
|
|
1500
|
+
timestamp?: string | number;
|
|
1501
|
+
eventType?: string;
|
|
1502
|
+
source?: string;
|
|
1503
|
+
headers?: Record<string, string>;
|
|
1504
|
+
maxRetries?: number;
|
|
1505
|
+
retryDelayMs?: number;
|
|
1506
|
+
timeoutMs?: number;
|
|
1507
|
+
signal?: AbortSignal;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
export interface RealtimeXWebhookReceipt {
|
|
1511
|
+
success: boolean;
|
|
1512
|
+
accepted: boolean;
|
|
1513
|
+
duplicate: boolean;
|
|
1514
|
+
deliveryId: string;
|
|
1515
|
+
threadId: string | number | null;
|
|
1516
|
+
taskId: string | number | null;
|
|
1517
|
+
[key: string]: unknown;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1460
1520
|
export declare class RealtimeXApiError extends Error {
|
|
1461
1521
|
status?: number;
|
|
1462
1522
|
statusText?: string;
|
|
@@ -1464,6 +1524,21 @@ export declare class RealtimeXApiError extends Error {
|
|
|
1464
1524
|
response: Response;
|
|
1465
1525
|
}
|
|
1466
1526
|
|
|
1527
|
+
export declare class RealtimeXWebhookError extends Error {
|
|
1528
|
+
status?: number;
|
|
1529
|
+
statusText?: string;
|
|
1530
|
+
body: unknown;
|
|
1531
|
+
response: Response | null;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
export declare class RealtimeXWebhookClient {
|
|
1535
|
+
constructor(options?: RealtimeXWebhookClientOptions);
|
|
1536
|
+
trigger(
|
|
1537
|
+
payload: unknown,
|
|
1538
|
+
options?: RealtimeXWebhookTriggerOptions
|
|
1539
|
+
): Promise<RealtimeXWebhookReceipt>;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1467
1542
|
export declare class RealtimeXClient {
|
|
1468
1543
|
constructor(options?: RealtimeXClientOptions);
|
|
1469
1544
|
request(operationName: string, options?: RealtimeXRequestOptions): Promise<unknown>;
|
|
@@ -1533,6 +1608,9 @@ export declare class RealtimeXClient {
|
|
|
1533
1608
|
/** Get one workspace by exact workspace slug. */
|
|
1534
1609
|
getWorkspace(options?: GetWorkspaceOptions): Promise<GetWorkspaceResponse>;
|
|
1535
1610
|
getWorkspace(workspaceSlug: string, options?: Omit<GetWorkspaceOptions, 'params'>): Promise<GetWorkspaceResponse>;
|
|
1611
|
+
/** Verify the shared Project/global Goal kickoff composer, routing, attachment authorization, retry, preview, and responsive layouts. */
|
|
1612
|
+
goalKickoffComposer(options?: GoalKickoffComposerOptions): Promise<GoalKickoffComposerResponse>;
|
|
1613
|
+
goalKickoffComposer(body: GoalKickoffComposerBody, options?: Omit<GoalKickoffComposerOptions, 'body'>): Promise<GoalKickoffComposerResponse>;
|
|
1536
1614
|
/** Install a plugin from a local source directory on the same machine as the server. Pass an absolute path containing realtimex.plugin.json. Pass force=true to replace an already-installed version; its saved configuration (including secrets) is preserved. */
|
|
1537
1615
|
installPlugin(options?: InstallPluginOptions): Promise<InstallPluginResponse>;
|
|
1538
1616
|
installPlugin(body: InstallPluginBody, options?: Omit<InstallPluginOptions, 'body'>): Promise<InstallPluginResponse>;
|
|
@@ -1689,6 +1767,9 @@ export declare class RealtimeXClient {
|
|
|
1689
1767
|
export declare function createRealtimeXClient(
|
|
1690
1768
|
options?: RealtimeXClientOptions
|
|
1691
1769
|
): RealtimeXClient;
|
|
1770
|
+
export declare function createRealtimeXWebhookClient(
|
|
1771
|
+
options?: RealtimeXWebhookClientOptions
|
|
1772
|
+
): RealtimeXWebhookClient;
|
|
1692
1773
|
export declare const createClient: typeof createRealtimeXClient;
|
|
1693
1774
|
export declare const operations: Record<
|
|
1694
1775
|
string,
|
package/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
|
|
3
5
|
const operations = {
|
|
4
6
|
"approveChannelPairingCode": {
|
|
5
7
|
"method": "POST",
|
|
@@ -268,6 +270,14 @@ const operations = {
|
|
|
268
270
|
],
|
|
269
271
|
"hasBody": false
|
|
270
272
|
},
|
|
273
|
+
"goalKickoffComposer": {
|
|
274
|
+
"method": "POST",
|
|
275
|
+
"path": "/goal-kickoff-composer",
|
|
276
|
+
"pathParams": [],
|
|
277
|
+
"queryParams": [],
|
|
278
|
+
"headerParams": [],
|
|
279
|
+
"hasBody": true
|
|
280
|
+
},
|
|
271
281
|
"installPlugin": {
|
|
272
282
|
"method": "POST",
|
|
273
283
|
"path": "/install-plugin",
|
|
@@ -876,6 +886,17 @@ class RealtimeXApiError extends Error {
|
|
|
876
886
|
}
|
|
877
887
|
}
|
|
878
888
|
|
|
889
|
+
class RealtimeXWebhookError extends Error {
|
|
890
|
+
constructor(message, response = null, body = null, cause = null) {
|
|
891
|
+
super(message, cause ? { cause } : undefined);
|
|
892
|
+
this.name = 'RealtimeXWebhookError';
|
|
893
|
+
this.status = response && response.status;
|
|
894
|
+
this.statusText = response && response.statusText;
|
|
895
|
+
this.body = body;
|
|
896
|
+
this.response = response;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
879
900
|
function joinUrl(baseUrl, pathname) {
|
|
880
901
|
const base = String(baseUrl || '').replace(/\/+$/g, '');
|
|
881
902
|
const path = String(pathname || '').replace(/^\/+/, '');
|
|
@@ -929,6 +950,220 @@ async function parseResponseBody(response) {
|
|
|
929
950
|
}
|
|
930
951
|
}
|
|
931
952
|
|
|
953
|
+
function normalizeWebhookEndpointUrl(value) {
|
|
954
|
+
const normalized = String(value || '').trim();
|
|
955
|
+
if (!normalized) {
|
|
956
|
+
throw new Error(
|
|
957
|
+
'RealtimeX webhook URL is unavailable; pass { endpointUrl } or set REALTIMEX_WEBHOOK_URL.'
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
const parsed = new URL(normalized);
|
|
961
|
+
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
962
|
+
throw new Error('RealtimeX webhook URL must use http or https.');
|
|
963
|
+
}
|
|
964
|
+
if (parsed.username || parsed.password) {
|
|
965
|
+
throw new Error('RealtimeX webhook URL must not contain embedded credentials.');
|
|
966
|
+
}
|
|
967
|
+
return parsed.toString();
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
function normalizeRetryCount(value, fallback = 2) {
|
|
971
|
+
const parsed = Number(value);
|
|
972
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > 10) return fallback;
|
|
973
|
+
return parsed;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
function normalizeTimeout(value, fallback = 15000) {
|
|
977
|
+
const parsed = Number(value);
|
|
978
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
|
979
|
+
return Math.min(Math.floor(parsed), 120000);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
function waitForRetry(delayMs, signal) {
|
|
983
|
+
const delay = Math.max(0, Number(delayMs) || 0);
|
|
984
|
+
if (delay === 0) return Promise.resolve();
|
|
985
|
+
return new Promise((resolve, reject) => {
|
|
986
|
+
const finish = () => {
|
|
987
|
+
if (signal) signal.removeEventListener('abort', abort);
|
|
988
|
+
resolve();
|
|
989
|
+
};
|
|
990
|
+
const timeout = setTimeout(finish, delay);
|
|
991
|
+
const abort = () => {
|
|
992
|
+
clearTimeout(timeout);
|
|
993
|
+
signal.removeEventListener('abort', abort);
|
|
994
|
+
reject(signal.reason || new Error('Webhook request aborted.'));
|
|
995
|
+
};
|
|
996
|
+
if (signal) {
|
|
997
|
+
if (signal.aborted) return abort();
|
|
998
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
function createAttemptSignal(externalSignal, timeoutMs) {
|
|
1004
|
+
const controller = new AbortController();
|
|
1005
|
+
const abortFromExternal = () => {
|
|
1006
|
+
controller.abort(externalSignal.reason || new Error('Webhook request aborted.'));
|
|
1007
|
+
};
|
|
1008
|
+
if (externalSignal) {
|
|
1009
|
+
if (externalSignal.aborted) abortFromExternal();
|
|
1010
|
+
else externalSignal.addEventListener('abort', abortFromExternal, { once: true });
|
|
1011
|
+
}
|
|
1012
|
+
const timeout = setTimeout(
|
|
1013
|
+
() => controller.abort(new Error('Webhook request timed out.')),
|
|
1014
|
+
timeoutMs
|
|
1015
|
+
);
|
|
1016
|
+
return {
|
|
1017
|
+
signal: controller.signal,
|
|
1018
|
+
cleanup() {
|
|
1019
|
+
clearTimeout(timeout);
|
|
1020
|
+
if (externalSignal) {
|
|
1021
|
+
externalSignal.removeEventListener('abort', abortFromExternal);
|
|
1022
|
+
}
|
|
1023
|
+
},
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
class RealtimeXWebhookClient {
|
|
1028
|
+
constructor(options = {}) {
|
|
1029
|
+
const env = typeof process !== 'undefined' ? process.env || {} : {};
|
|
1030
|
+
this.endpointUrl = normalizeWebhookEndpointUrl(
|
|
1031
|
+
options.endpointUrl || options.url || env.REALTIMEX_WEBHOOK_URL
|
|
1032
|
+
);
|
|
1033
|
+
this.secret = String(options.secret || env.REALTIMEX_WEBHOOK_SECRET || '');
|
|
1034
|
+
if (!this.secret) {
|
|
1035
|
+
throw new Error(
|
|
1036
|
+
'RealtimeX webhook secret is unavailable; pass { secret } or set REALTIMEX_WEBHOOK_SECRET.'
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
this.fetch = options.fetch || globalThis.fetch;
|
|
1040
|
+
if (typeof this.fetch !== 'function') {
|
|
1041
|
+
throw new Error('A fetch implementation is required. Use Node 18+ or pass { fetch }.');
|
|
1042
|
+
}
|
|
1043
|
+
this.signatureHeader =
|
|
1044
|
+
options.signatureHeader ||
|
|
1045
|
+
env.REALTIMEX_WEBHOOK_SIGNATURE_HEADER ||
|
|
1046
|
+
'X-Webhook-Signature-256';
|
|
1047
|
+
this.signaturePrefix =
|
|
1048
|
+
options.signaturePrefix ?? env.REALTIMEX_WEBHOOK_SIGNATURE_PREFIX ?? 'sha256=';
|
|
1049
|
+
this.timestampHeader =
|
|
1050
|
+
options.timestampHeader ||
|
|
1051
|
+
env.REALTIMEX_WEBHOOK_TIMESTAMP_HEADER ||
|
|
1052
|
+
'X-Webhook-Timestamp';
|
|
1053
|
+
this.deliveryIdHeader =
|
|
1054
|
+
options.deliveryIdHeader ||
|
|
1055
|
+
env.REALTIMEX_WEBHOOK_DELIVERY_ID_HEADER ||
|
|
1056
|
+
'X-Webhook-Id';
|
|
1057
|
+
this.eventTypeHeader =
|
|
1058
|
+
options.eventTypeHeader ||
|
|
1059
|
+
env.REALTIMEX_WEBHOOK_EVENT_TYPE_HEADER ||
|
|
1060
|
+
'X-Webhook-Event';
|
|
1061
|
+
this.sourceHeader =
|
|
1062
|
+
options.sourceHeader ||
|
|
1063
|
+
env.REALTIMEX_WEBHOOK_SOURCE_HEADER ||
|
|
1064
|
+
'X-Webhook-Source';
|
|
1065
|
+
this.defaultEventType =
|
|
1066
|
+
options.eventType || env.REALTIMEX_WEBHOOK_EVENT_TYPE || 'realtimex.task';
|
|
1067
|
+
this.defaultSource =
|
|
1068
|
+
options.source || env.REALTIMEX_WEBHOOK_SOURCE || 'local-app';
|
|
1069
|
+
this.defaultHeaders = { ...(options.headers || {}) };
|
|
1070
|
+
this.maxRetries = normalizeRetryCount(options.maxRetries, 2);
|
|
1071
|
+
const configuredRetryDelay = Number(options.retryDelayMs);
|
|
1072
|
+
this.retryDelayMs = Number.isFinite(configuredRetryDelay) && configuredRetryDelay >= 0
|
|
1073
|
+
? configuredRetryDelay
|
|
1074
|
+
: 250;
|
|
1075
|
+
this.timeoutMs = normalizeTimeout(options.timeoutMs, 15000);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
async trigger(payload, options = {}) {
|
|
1079
|
+
if (payload === undefined) {
|
|
1080
|
+
throw new Error('RealtimeX webhook payload is required.');
|
|
1081
|
+
}
|
|
1082
|
+
const serialized = typeof payload === 'string' ? payload : JSON.stringify(payload);
|
|
1083
|
+
if (serialized === undefined) {
|
|
1084
|
+
throw new Error('RealtimeX webhook payload is not JSON serializable.');
|
|
1085
|
+
}
|
|
1086
|
+
const body = Buffer.from(serialized, 'utf8');
|
|
1087
|
+
const deliveryId = String(options.deliveryId || crypto.randomUUID());
|
|
1088
|
+
const timestamp = String(
|
|
1089
|
+
options.timestamp || Math.floor(Date.now() / 1000)
|
|
1090
|
+
);
|
|
1091
|
+
const signature = crypto
|
|
1092
|
+
.createHmac('sha256', this.secret)
|
|
1093
|
+
.update(body)
|
|
1094
|
+
.digest('hex');
|
|
1095
|
+
const headers = {
|
|
1096
|
+
...this.defaultHeaders,
|
|
1097
|
+
...(options.headers || {}),
|
|
1098
|
+
'content-type': 'application/json',
|
|
1099
|
+
[this.signatureHeader]: String(this.signaturePrefix || '') + signature,
|
|
1100
|
+
[this.timestampHeader]: timestamp,
|
|
1101
|
+
[this.deliveryIdHeader]: deliveryId,
|
|
1102
|
+
[this.eventTypeHeader]: String(options.eventType || this.defaultEventType),
|
|
1103
|
+
[this.sourceHeader]: String(options.source || this.defaultSource),
|
|
1104
|
+
};
|
|
1105
|
+
const maxRetries = normalizeRetryCount(options.maxRetries, this.maxRetries);
|
|
1106
|
+
const retryDelayMs =
|
|
1107
|
+
options.retryDelayMs === undefined
|
|
1108
|
+
? this.retryDelayMs
|
|
1109
|
+
: Math.max(0, Number(options.retryDelayMs) || 0);
|
|
1110
|
+
const timeoutMs = normalizeTimeout(options.timeoutMs, this.timeoutMs);
|
|
1111
|
+
|
|
1112
|
+
for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
|
|
1113
|
+
const attemptSignal = createAttemptSignal(options.signal, timeoutMs);
|
|
1114
|
+
try {
|
|
1115
|
+
const response = await this.fetch(this.endpointUrl, {
|
|
1116
|
+
method: 'POST',
|
|
1117
|
+
headers,
|
|
1118
|
+
body,
|
|
1119
|
+
signal: attemptSignal.signal,
|
|
1120
|
+
});
|
|
1121
|
+
const responseBody = await parseResponseBody(response);
|
|
1122
|
+
if (response.status >= 500 && attempt < maxRetries) {
|
|
1123
|
+
await waitForRetry(retryDelayMs * (attempt + 1), options.signal);
|
|
1124
|
+
continue;
|
|
1125
|
+
}
|
|
1126
|
+
if (!response.ok) {
|
|
1127
|
+
throw new RealtimeXWebhookError(
|
|
1128
|
+
'RealtimeX webhook request failed: ' +
|
|
1129
|
+
response.status +
|
|
1130
|
+
' ' +
|
|
1131
|
+
response.statusText,
|
|
1132
|
+
response,
|
|
1133
|
+
responseBody
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
return responseBody;
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
if (error instanceof RealtimeXWebhookError) throw error;
|
|
1139
|
+
if (options.signal && options.signal.aborted) {
|
|
1140
|
+
throw new RealtimeXWebhookError(
|
|
1141
|
+
'RealtimeX webhook request aborted.',
|
|
1142
|
+
null,
|
|
1143
|
+
null,
|
|
1144
|
+
error
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
if (attempt >= maxRetries) {
|
|
1148
|
+
const timedOut = attemptSignal.signal.aborted;
|
|
1149
|
+
throw new RealtimeXWebhookError(
|
|
1150
|
+
timedOut
|
|
1151
|
+
? 'RealtimeX webhook request timed out.'
|
|
1152
|
+
: 'RealtimeX webhook request failed: ' + (error.message || String(error)),
|
|
1153
|
+
null,
|
|
1154
|
+
null,
|
|
1155
|
+
error
|
|
1156
|
+
);
|
|
1157
|
+
}
|
|
1158
|
+
await waitForRetry(retryDelayMs * (attempt + 1), options.signal);
|
|
1159
|
+
} finally {
|
|
1160
|
+
attemptSignal.cleanup();
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
throw new RealtimeXWebhookError('RealtimeX webhook request failed.');
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
932
1167
|
function isPlainObject(value) {
|
|
933
1168
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
934
1169
|
}
|
|
@@ -1217,6 +1452,13 @@ class RealtimeXClient {
|
|
|
1217
1452
|
);
|
|
1218
1453
|
}
|
|
1219
1454
|
|
|
1455
|
+
goalKickoffComposer(...args) {
|
|
1456
|
+
return this.request(
|
|
1457
|
+
"goalKickoffComposer",
|
|
1458
|
+
normalizeOperationOptions(operations["goalKickoffComposer"], args)
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1220
1462
|
installPlugin(...args) {
|
|
1221
1463
|
return this.request(
|
|
1222
1464
|
"installPlugin",
|
|
@@ -1593,11 +1835,18 @@ function createRealtimeXClient(options = {}) {
|
|
|
1593
1835
|
return new RealtimeXClient(options);
|
|
1594
1836
|
}
|
|
1595
1837
|
|
|
1838
|
+
function createRealtimeXWebhookClient(options = {}) {
|
|
1839
|
+
return new RealtimeXWebhookClient(options);
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1596
1842
|
module.exports = {
|
|
1597
1843
|
RealtimeXApiError,
|
|
1598
1844
|
RealtimeXClient,
|
|
1845
|
+
RealtimeXWebhookClient,
|
|
1846
|
+
RealtimeXWebhookError,
|
|
1599
1847
|
createClient: createRealtimeXClient,
|
|
1600
1848
|
createRealtimeXClient,
|
|
1849
|
+
createRealtimeXWebhookClient,
|
|
1601
1850
|
operations,
|
|
1602
|
-
version: "2.0.
|
|
1851
|
+
version: "2.0.31",
|
|
1603
1852
|
};
|
package/package.json
CHANGED
|
@@ -20,15 +20,15 @@ This skill drives the `realtimex-pp-cli` binary. Verify the CLI is installed and
|
|
|
20
20
|
|
|
21
21
|
1. Install or reinstall the pinned version via npm:
|
|
22
22
|
```bash
|
|
23
|
-
npm install -g @realtimex/pp-cli@2.0.
|
|
23
|
+
npm install -g @realtimex/pp-cli@2.0.31
|
|
24
24
|
```
|
|
25
25
|
2. Verify the exact version:
|
|
26
26
|
```bash
|
|
27
27
|
realtimex-pp-cli --version
|
|
28
28
|
```
|
|
29
|
-
The output must be `realtimex-pp-cli 2.0.
|
|
29
|
+
The output must be `realtimex-pp-cli 2.0.31`.
|
|
30
30
|
|
|
31
|
-
If `--version` reports "command not found" after install, the npm global bin directory is not on `$PATH`. If it reports any version other than `2.0.
|
|
31
|
+
If `--version` reports "command not found" after install, the npm global bin directory is not on `$PATH`. If it reports any version other than `2.0.31`, reinstall with the pinned npm command above. Do not proceed with skill commands until exact-version verification succeeds.
|
|
32
32
|
|
|
33
33
|
* Always run first:
|
|
34
34
|
|
|
@@ -126,6 +126,10 @@ If `--version` reports "command not found" after install, the npm global bin dir
|
|
|
126
126
|
|
|
127
127
|
- `realtimex-pp-cli get-workspace <workspaceSlug>` — Get one workspace by exact workspace slug.
|
|
128
128
|
|
|
129
|
+
**goal-kickoff-composer** — Manage goal kickoff composer
|
|
130
|
+
|
|
131
|
+
- `realtimex-pp-cli goal-kickoff-composer` — Verify the shared Project/global Goal kickoff composer, routing, attachment authorization, retry, preview
|
|
132
|
+
|
|
129
133
|
**install-plugin** — Manage install plugin
|
|
130
134
|
|
|
131
135
|
- `realtimex-pp-cli install-plugin` — Install a plugin from a local source directory on the same machine as the server.
|
|
@@ -460,9 +464,9 @@ Verify: `claude mcp list`
|
|
|
460
464
|
```bash
|
|
461
465
|
realtimex-pp-cli --version
|
|
462
466
|
```
|
|
463
|
-
If the command is missing or the output is not exactly `realtimex-pp-cli 2.0.
|
|
467
|
+
If the command is missing or the output is not exactly `realtimex-pp-cli 2.0.31`, reinstall the pinned version:
|
|
464
468
|
```bash
|
|
465
|
-
npm install -g @realtimex/pp-cli@2.0.
|
|
469
|
+
npm install -g @realtimex/pp-cli@2.0.31
|
|
466
470
|
```
|
|
467
471
|
Then run `realtimex-pp-cli --version` again and proceed only after exact-version verification succeeds.
|
|
468
472
|
2. Match the user query to the best command from the Unique Capabilities and Command Reference above.
|