@openclaw/clickclack 2026.9.7 → 2026.10.1-beta.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.
- package/dist/.setup/{channel-Bcwtohk7.mjs → channel-DI3hKiSg.mjs} +42 -142
- package/dist/.setup/{resolve-BHGLohni.mjs → resolve-DPtjHQHt.mjs} +43 -74
- package/dist/.setup/{runtime-api-BvP8DrPQ.mjs → runtime-api-Dm_MQHNq.mjs} +127 -189
- package/dist/.setup/secret-contract-CF7TKtkU.mjs +26 -0
- package/dist/.setup/{secret-contract-api-C1QwGlzF.mjs → secret-contract-api-CBcsgIYZ.mjs} +1 -1
- package/dist/.setup/{setup-claim-Cx8knvXs.mjs → setup-claim-Cfv5ikVH.mjs} +1 -1
- package/dist/.setup/{setup-plugin-api-BH_nw-AP.mjs → setup-plugin-api-BXhjNJRg.mjs} +1 -1
- package/dist/.setup/{setup-plugin-api-C9QcBJuW.mjs → setup-plugin-api-CqfAb-CU.mjs} +1 -1
- package/dist/.setup/{setup-surface-BW1Q06w5.mjs → setup-surface-DcF_7-VV.mjs} +6 -21
- package/dist/.setup/{setup-verify-Msgd70_M.mjs → setup-verify-POQZk8SG.mjs} +5 -14
- package/dist/api.js +3 -3
- package/dist/channel-plugin-api.js +1 -1
- package/dist/doctor-contract-api.js +6 -0
- package/dist/index.js +1 -1
- package/dist/runtime-api.js +4 -4
- package/dist/secret-contract-api.js +1 -1
- package/dist/setup-entry.js +2 -2
- package/dist/setup-plugin-api.js +1 -1
- package/package.json +5 -5
- package/dist/.setup/secret-contract-BKkzzjBA.mjs +0 -35
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { n as __reExport, t as __exportAll } from "./rolldown-runtime-B4FMCO8f.mjs";
|
|
2
|
-
import { c as CLICKCLACK_CHANNEL_ID, d as DEFAULT_ACCOUNT_ID, f as isClickClackAccountCurrent, g as resolveClickClackAccountConfig, h as resolveClickClackAccount, l as clickClackConfigAdapter, m as listEnabledClickClackAccounts, n as clickClackSetupContract, s as clickClackConfigSchema, t as clickClackSetupWizard, u as clickClackMeta } from "./setup-surface-
|
|
3
|
-
import {
|
|
4
|
-
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-
|
|
2
|
+
import { c as CLICKCLACK_CHANNEL_ID, d as DEFAULT_ACCOUNT_ID, f as isClickClackAccountCurrent, g as resolveClickClackAccountConfig, h as resolveClickClackAccount, l as clickClackConfigAdapter, m as listEnabledClickClackAccounts, n as clickClackSetupContract, s as clickClackConfigSchema, t as clickClackSetupWizard, u as clickClackMeta } from "./setup-surface-DcF_7-VV.mjs";
|
|
3
|
+
import { a as createClickClackClient, i as ClickClackHttpError, n as resolveChannelId, r as resolveWorkspaceId, s as normalizeClickClackCorrelationId } from "./resolve-DPtjHQHt.mjs";
|
|
4
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-CF7TKtkU.mjs";
|
|
5
5
|
import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/account-helpers";
|
|
6
6
|
import { parseDateStringTimestampMs } from "openclaw/plugin-sdk/number-runtime";
|
|
7
7
|
import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
|
|
8
|
-
import { readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
8
|
+
import { normalizeTrimmedStringList, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
9
|
import { buildChannelOutboundSessionRoute, buildThreadAwareOutboundSessionRoute, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
10
10
|
import { buildChannelProgressDraftLine, createChannelMessageReplyPipeline, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, deriveDurableFinalDeliveryRequirements, formatChannelProgressDraftLineForEntry, isCompleteAgentPreamble } from "openclaw/plugin-sdk/channel-outbound";
|
|
11
11
|
import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
@@ -18,13 +18,15 @@ import { parseAccessGroupAllowFromEntry } from "openclaw/plugin-sdk/access-group
|
|
|
18
18
|
import { formatNormalizedAllowFromEntries, resolveAllowlistMatchByCandidates } from "openclaw/plugin-sdk/allow-from";
|
|
19
19
|
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
20
20
|
import { createHash, randomUUID } from "node:crypto";
|
|
21
|
+
import { createAsyncLock } from "openclaw/plugin-sdk/async-lock-runtime";
|
|
21
22
|
import { truncateCodePoints } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
22
23
|
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
23
24
|
import { listNativeCommandSpecsForConfig } from "openclaw/plugin-sdk/native-command-registry";
|
|
24
25
|
import { buildChannelInboundEventContext, createChannelInboundEnvelopeBuilder, createChannelPartialDeliveryError, recordChannelBotPairLoopAndCheckSuppression } from "openclaw/plugin-sdk/channel-inbound";
|
|
25
26
|
import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
|
|
26
27
|
import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
|
|
27
|
-
import {
|
|
28
|
+
import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
29
|
+
import { raceWithTimeout } from "openclaw/plugin-sdk/time-runtime";
|
|
28
30
|
//#region src/channels/mention-gating.ts
|
|
29
31
|
function resolveBotThreadMentionPolicy(params) {
|
|
30
32
|
if (!params.isBotOwnedThread || params.requireMentionInBotThreads === void 0) return {
|
|
@@ -56,14 +58,12 @@ function withGenerationStore(runtime, run) {
|
|
|
56
58
|
owner = {
|
|
57
59
|
store,
|
|
58
60
|
...!store.observe || !store.compareAndApply ? { native: runtime.state.openSyncKeyedStore(GENERATION_STORE_OPTIONS) } : {},
|
|
59
|
-
|
|
61
|
+
withLock: createAsyncLock()
|
|
60
62
|
};
|
|
61
63
|
storesByRuntime$2.set(runtime, owner);
|
|
62
64
|
}
|
|
63
65
|
const currentOwner = owner;
|
|
64
|
-
|
|
65
|
-
owner.tail = current.then(() => void 0, () => void 0);
|
|
66
|
-
return current;
|
|
66
|
+
return currentOwner.withLock(() => run(currentOwner));
|
|
67
67
|
}
|
|
68
68
|
function mutateGeneration(runtime, sessionKey, decide) {
|
|
69
69
|
return withGenerationStore(runtime, async ({ store, native }) => {
|
|
@@ -248,12 +248,7 @@ function attachBindingToCurrentActiveSession(params) {
|
|
|
248
248
|
readConsistency: "latest"
|
|
249
249
|
});
|
|
250
250
|
if (!entry?.sessionId || entry.archivedAt !== void 0) return;
|
|
251
|
-
if (entry.sessionId === params.binding.sessionId)
|
|
252
|
-
if (params.binding.detachedAt === void 0) return params.binding;
|
|
253
|
-
const { detachedAt: _detachedAt, ...attached } = params.binding;
|
|
254
|
-
params.store.set(params.sessionKey, attached);
|
|
255
|
-
return attached;
|
|
256
|
-
}
|
|
251
|
+
if (entry.sessionId === params.binding.sessionId && params.binding.detachedAt === void 0) return params.binding;
|
|
257
252
|
const { detachedAt: _detachedAt, ...retained } = params.binding;
|
|
258
253
|
const attached = {
|
|
259
254
|
...retained,
|
|
@@ -546,12 +541,6 @@ function resolveClickClackGroupPolicy(params) {
|
|
|
546
541
|
}
|
|
547
542
|
//#endregion
|
|
548
543
|
//#region extensions/clickclack/src/mention-facts.ts
|
|
549
|
-
/**
|
|
550
|
-
* Detects whether a ClickClack group message contains a direct mention of the
|
|
551
|
-
* current account.
|
|
552
|
-
*
|
|
553
|
-
* Pure helper – no side effects, no runtime imports.
|
|
554
|
-
*/
|
|
555
544
|
const CLICKCLACK_MENTION_PATTERN = /(?:^|[^a-z0-9_@-])@([a-z0-9][a-z0-9_-]{1,31})(?![a-z0-9_-])/giu;
|
|
556
545
|
function buildLocalMentionRegexes(params) {
|
|
557
546
|
if (params.mentionPatterns.length === 0) return [];
|
|
@@ -574,18 +563,6 @@ function buildLocalMentionRegexes(params) {
|
|
|
574
563
|
function resolveMentionHandles(body) {
|
|
575
564
|
return [...body.matchAll(CLICKCLACK_MENTION_PATTERN)].map((match) => match[1]?.toLowerCase()).filter((handle) => Boolean(handle));
|
|
576
565
|
}
|
|
577
|
-
/**
|
|
578
|
-
* Builds mention facts for a ClickClack message.
|
|
579
|
-
*
|
|
580
|
-
* Rules:
|
|
581
|
-
* - DMs always have canDetectMention: false, wasMentioned: false
|
|
582
|
-
* (DMs bypass mention gating).
|
|
583
|
-
* - Group messages: canDetectMention: true when body text is available.
|
|
584
|
-
* - Checks the message body against shared and account-local mention patterns.
|
|
585
|
-
* - If botHandle is provided and the message body contains its ClickClack
|
|
586
|
-
* `@handle`, treat it as a mention.
|
|
587
|
-
* - Shared patterns default to the routed agent's identity name when none are configured.
|
|
588
|
-
*/
|
|
589
566
|
function resolveClickClackMentionFacts(params) {
|
|
590
567
|
const { isDirect, body, mentionPatterns, botHandle, cfg, agentId, channelId } = params;
|
|
591
568
|
if (isDirect) return {
|
|
@@ -783,10 +760,6 @@ async function resolvePreparedInboundRoute(params) {
|
|
|
783
760
|
revoked: discussionResolution.state === "revoked"
|
|
784
761
|
};
|
|
785
762
|
}
|
|
786
|
-
/**
|
|
787
|
-
* Resolves whether a ClickClack message should enter the agent pipeline and
|
|
788
|
-
* whether its command-style body may run tools.
|
|
789
|
-
*/
|
|
790
763
|
async function resolveClickClackInboundAccess(params) {
|
|
791
764
|
const runtime = getClickClackRuntime();
|
|
792
765
|
const rootPolicyConfigured = resolveClickClackGroupPolicy({
|
|
@@ -1024,11 +997,6 @@ async function syncClickClackCommandMenu(params) {
|
|
|
1024
997
|
}
|
|
1025
998
|
//#endregion
|
|
1026
999
|
//#region extensions/clickclack/src/activity.ts
|
|
1027
|
-
/**
|
|
1028
|
-
* Publishes agent activity (streamed commentary + tool progress) into
|
|
1029
|
-
* ClickClack as durable `agent_commentary` / `agent_tool` message rows,
|
|
1030
|
-
* coalesced so one logical step becomes one row instead of a row per frame.
|
|
1031
|
-
*/
|
|
1032
1000
|
const CLICKCLACK_COMMENTARY_FLUSH_MS = 700;
|
|
1033
1001
|
/** Item kinds rendered as agent_tool rows; everything else is commentary. */
|
|
1034
1002
|
const TOOL_ITEM_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -1067,18 +1035,9 @@ function commentaryBody(payload) {
|
|
|
1067
1035
|
}
|
|
1068
1036
|
function activityBody(payload) {
|
|
1069
1037
|
const line = formatChannelProgressDraftLineForEntry(void 0, {
|
|
1038
|
+
...payload,
|
|
1070
1039
|
event: "item",
|
|
1071
|
-
|
|
1072
|
-
toolCallId: payload.toolCallId,
|
|
1073
|
-
itemKind: payload.kind,
|
|
1074
|
-
title: payload.title,
|
|
1075
|
-
name: payload.name,
|
|
1076
|
-
phase: payload.phase,
|
|
1077
|
-
status: payload.status,
|
|
1078
|
-
summary: payload.summary,
|
|
1079
|
-
progressText: payload.progressText,
|
|
1080
|
-
meta: payload.meta,
|
|
1081
|
-
commandBearing: payload.commandBearing
|
|
1040
|
+
itemKind: payload.kind
|
|
1082
1041
|
})?.trim();
|
|
1083
1042
|
if (line) return line;
|
|
1084
1043
|
const head = payload.name?.trim() || payload.title?.trim();
|
|
@@ -1229,28 +1188,7 @@ function createClickClackActivityPublisher(params) {
|
|
|
1229
1188
|
}
|
|
1230
1189
|
//#endregion
|
|
1231
1190
|
//#region extensions/clickclack/src/outbound.ts
|
|
1232
|
-
/**
|
|
1233
|
-
* Outbound ClickClack delivery helpers for channel messages, thread replies,
|
|
1234
|
-
* and direct messages.
|
|
1235
|
-
*/
|
|
1236
1191
|
const CLICKCLACK_MAX_UPLOAD_BYTES = 67108864;
|
|
1237
|
-
const CLICKCLACK_FORMAT_PROFILE = FormatCapabilityProfile.define({
|
|
1238
|
-
mechanism: "markdown",
|
|
1239
|
-
chunk: {
|
|
1240
|
-
limit: 1048576,
|
|
1241
|
-
unit: "bytes"
|
|
1242
|
-
}
|
|
1243
|
-
});
|
|
1244
|
-
function renderClickClackMarkdown(markdown) {
|
|
1245
|
-
return renderMarkdownWithMarkers({
|
|
1246
|
-
text: markdown,
|
|
1247
|
-
styles: [],
|
|
1248
|
-
links: []
|
|
1249
|
-
}, {
|
|
1250
|
-
styleMarkers: {},
|
|
1251
|
-
escapeText: (text) => text
|
|
1252
|
-
}, CLICKCLACK_FORMAT_PROFILE);
|
|
1253
|
-
}
|
|
1254
1192
|
async function createTargetMessage(params) {
|
|
1255
1193
|
const parsed = parseClickClackTarget(params.to);
|
|
1256
1194
|
const explicitThreadId = params.threadId == null ? "" : String(params.threadId);
|
|
@@ -1340,7 +1278,7 @@ function createOutboundContext(params) {
|
|
|
1340
1278
|
* message id, or undefined when sanitization removes all content.
|
|
1341
1279
|
*/
|
|
1342
1280
|
async function sendClickClackText(params) {
|
|
1343
|
-
const text =
|
|
1281
|
+
const text = sanitizeAssistantVisibleText(params.text);
|
|
1344
1282
|
if (!text) return;
|
|
1345
1283
|
const { account, client } = createOutboundContext(params);
|
|
1346
1284
|
return (await createTargetMessage({
|
|
@@ -1351,32 +1289,25 @@ async function sendClickClackText(params) {
|
|
|
1351
1289
|
threadId: params.threadId,
|
|
1352
1290
|
replyToId: params.replyToId,
|
|
1353
1291
|
provenance: params.provenance,
|
|
1354
|
-
nonce: textDeliveryNonce(
|
|
1355
|
-
deliveryQueueId: params.deliveryQueueId,
|
|
1356
|
-
deliveryPartIndex: params.deliveryPartIndex
|
|
1357
|
-
}),
|
|
1292
|
+
nonce: textDeliveryNonce(params),
|
|
1358
1293
|
onPlatformSendDispatch: params.onPlatformSendDispatch,
|
|
1359
1294
|
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
1360
1295
|
})).id;
|
|
1361
1296
|
}
|
|
1362
|
-
/** Resolves, uploads, sends, then attaches one file to a ClickClack message. */
|
|
1363
1297
|
async function sendClickClackMedia(params) {
|
|
1364
|
-
const nonces = mediaDeliveryNonces(
|
|
1365
|
-
deliveryQueueId: params.deliveryQueueId,
|
|
1366
|
-
deliveryPartIndex: params.deliveryPartIndex
|
|
1367
|
-
});
|
|
1298
|
+
const nonces = mediaDeliveryNonces(params);
|
|
1368
1299
|
const { account, client } = createOutboundContext(params);
|
|
1369
|
-
const
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
maxBytes,
|
|
1300
|
+
const mediaLoadOptions = {
|
|
1301
|
+
maxBytes: Math.min(resolveChannelMediaMaxBytes({
|
|
1302
|
+
cfg: params.cfg,
|
|
1303
|
+
accountId: account.accountId,
|
|
1304
|
+
resolveChannelLimitMb: () => account.config.mediaMaxMb
|
|
1305
|
+
}) ?? CLICKCLACK_MAX_UPLOAD_BYTES, CLICKCLACK_MAX_UPLOAD_BYTES),
|
|
1376
1306
|
mediaAccess: params.mediaAccess,
|
|
1377
1307
|
mediaLocalRoots: params.mediaLocalRoots,
|
|
1378
1308
|
mediaReadFile: params.mediaReadFile
|
|
1379
|
-
}
|
|
1309
|
+
};
|
|
1310
|
+
const preloadedMedia = nonces.upload ? void 0 : await loadOutboundMediaFromUrl(params.mediaUrl, mediaLoadOptions);
|
|
1380
1311
|
const workspaceId = await resolveWorkspaceId(client, account.workspace);
|
|
1381
1312
|
let upload = nonces.upload ? await client.findUploadByNonce({
|
|
1382
1313
|
workspaceId,
|
|
@@ -1384,12 +1315,7 @@ async function sendClickClackMedia(params) {
|
|
|
1384
1315
|
}) : void 0;
|
|
1385
1316
|
let mediaFilename = preloadedMedia?.fileName?.trim();
|
|
1386
1317
|
if (!upload) {
|
|
1387
|
-
const media = preloadedMedia ?? await loadOutboundMediaFromUrl(params.mediaUrl,
|
|
1388
|
-
maxBytes,
|
|
1389
|
-
mediaAccess: params.mediaAccess,
|
|
1390
|
-
mediaLocalRoots: params.mediaLocalRoots,
|
|
1391
|
-
mediaReadFile: params.mediaReadFile
|
|
1392
|
-
});
|
|
1318
|
+
const media = preloadedMedia ?? await loadOutboundMediaFromUrl(params.mediaUrl, mediaLoadOptions);
|
|
1393
1319
|
const contentType = media.contentType?.trim() || "application/octet-stream";
|
|
1394
1320
|
const filename = media.fileName?.trim() || `attachment${extensionForMime(contentType) ?? ""}`;
|
|
1395
1321
|
mediaFilename = filename;
|
|
@@ -1401,7 +1327,7 @@ async function sendClickClackMedia(params) {
|
|
|
1401
1327
|
...nonces.upload ? { nonce: nonces.upload } : {}
|
|
1402
1328
|
});
|
|
1403
1329
|
}
|
|
1404
|
-
const text =
|
|
1330
|
+
const text = sanitizeAssistantVisibleText(params.text) || mediaFilename || upload.filename || "attachment";
|
|
1405
1331
|
const message = await createTargetMessage({
|
|
1406
1332
|
client,
|
|
1407
1333
|
workspaceId,
|
|
@@ -1442,12 +1368,6 @@ async function sendClickClackMedia(params) {
|
|
|
1442
1368
|
}
|
|
1443
1369
|
return message.id;
|
|
1444
1370
|
}
|
|
1445
|
-
function collectReconciliationMediaUrls(ctx) {
|
|
1446
|
-
const planned = ctx.renderedBatchPlan?.items[0]?.mediaUrls;
|
|
1447
|
-
if (planned?.length) return planned.map((url) => url.trim()).filter(Boolean);
|
|
1448
|
-
const payload = ctx.payloads[0];
|
|
1449
|
-
return [payload?.mediaUrl, ...payload?.mediaUrls ?? []].map((url) => url?.trim()).filter((url) => Boolean(url));
|
|
1450
|
-
}
|
|
1451
1371
|
/**
|
|
1452
1372
|
* Completes an unknown durable send through ClickClack's message/upload nonces.
|
|
1453
1373
|
* Media recovery never rereads the original source after restart.
|
|
@@ -1457,14 +1377,15 @@ async function reconcileClickClackUnknownSend(ctx) {
|
|
|
1457
1377
|
status: "unresolved",
|
|
1458
1378
|
error: "ClickClack reconciliation requires exactly one payload"
|
|
1459
1379
|
};
|
|
1460
|
-
const
|
|
1380
|
+
const payload = ctx.payloads[0];
|
|
1381
|
+
const plannedMediaUrls = ctx.renderedBatchPlan?.items[0]?.mediaUrls;
|
|
1382
|
+
const mediaUrls = normalizeTrimmedStringList(plannedMediaUrls?.length ? plannedMediaUrls : [payload?.mediaUrl, ...payload?.mediaUrls ?? []]);
|
|
1461
1383
|
const { account, client } = createOutboundContext({
|
|
1462
1384
|
cfg: ctx.cfg,
|
|
1463
1385
|
accountId: ctx.accountId
|
|
1464
1386
|
});
|
|
1465
1387
|
const workspaceId = await resolveWorkspaceId(client, account.workspace);
|
|
1466
1388
|
const effectiveReplyToId = ctx.effectiveReplyToId !== void 0 ? ctx.effectiveReplyToId : ctx.replyToMode === "off" ? void 0 : ctx.replyToId;
|
|
1467
|
-
const payload = ctx.payloads[0];
|
|
1468
1389
|
const caption = ctx.renderedBatchPlan?.items[0]?.text ?? payload?.text ?? "";
|
|
1469
1390
|
if (mediaUrls.length === 0) {
|
|
1470
1391
|
const nonce = textDeliveryNonce({
|
|
@@ -1548,11 +1469,6 @@ async function reconcileClickClackUnknownSend(ctx) {
|
|
|
1548
1469
|
}
|
|
1549
1470
|
//#endregion
|
|
1550
1471
|
//#region extensions/clickclack/src/progress.ts
|
|
1551
|
-
/**
|
|
1552
|
-
* Publishes ClickClack's native ephemeral agent.progress signal for one
|
|
1553
|
-
* OpenClaw turn. ClickClack renders this as its compact "Agent is
|
|
1554
|
-
* responding" status and the detailed progress lines above the composer.
|
|
1555
|
-
*/
|
|
1556
1472
|
function normalizedKind(payload) {
|
|
1557
1473
|
const kind = payload.kind?.trim().toLowerCase();
|
|
1558
1474
|
if (!kind || kind === "preamble" || kind === "analysis" || kind === "thinking" || kind === "reasoning" || kind === "missing") return "commentary";
|
|
@@ -1561,18 +1477,9 @@ function normalizedKind(payload) {
|
|
|
1561
1477
|
function progressText(payload) {
|
|
1562
1478
|
if (payload.kind !== "preamble" && payload.title) return payload.title;
|
|
1563
1479
|
const line = buildChannelProgressDraftLine({
|
|
1480
|
+
...payload,
|
|
1564
1481
|
event: "item",
|
|
1565
|
-
|
|
1566
|
-
toolCallId: payload.toolCallId,
|
|
1567
|
-
itemKind: payload.kind,
|
|
1568
|
-
title: payload.title,
|
|
1569
|
-
name: payload.name,
|
|
1570
|
-
phase: payload.phase,
|
|
1571
|
-
status: payload.status,
|
|
1572
|
-
summary: payload.summary,
|
|
1573
|
-
progressText: payload.progressText,
|
|
1574
|
-
meta: payload.meta,
|
|
1575
|
-
commandBearing: payload.commandBearing
|
|
1482
|
+
itemKind: payload.kind
|
|
1576
1483
|
})?.text?.trim();
|
|
1577
1484
|
if (line) return line;
|
|
1578
1485
|
return payload.progressText?.trim() || payload.summary?.trim() || payload.title?.trim() || payload.name?.trim() || payload.meta?.trim() || payload.status?.trim() || "Working";
|
|
@@ -1590,15 +1497,15 @@ function createLineIdResolver() {
|
|
|
1590
1497
|
if (identity) return `item:${identity}`;
|
|
1591
1498
|
const kind = normalizedKind(payload);
|
|
1592
1499
|
const anonymousLines = anonymousLinesByKind.get(kind) ?? [];
|
|
1593
|
-
const
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1500
|
+
const existingAnonymous = payload.phase?.trim().toLowerCase() === "start" ? void 0 : anonymousLines.toReversed().find((line) => line.active);
|
|
1501
|
+
const line = existingAnonymous ?? {
|
|
1502
|
+
id: `item:${kind}:${++anonymousSequence}`,
|
|
1503
|
+
active: true
|
|
1504
|
+
};
|
|
1505
|
+
if (!existingAnonymous) {
|
|
1506
|
+
anonymousLines.push(line);
|
|
1599
1507
|
anonymousLinesByKind.set(kind, anonymousLines);
|
|
1600
|
-
|
|
1601
|
-
})();
|
|
1508
|
+
}
|
|
1602
1509
|
if (isFinal(payload)) line.active = false;
|
|
1603
1510
|
return line.id;
|
|
1604
1511
|
};
|
|
@@ -1661,18 +1568,11 @@ function createClickClackAgentProgressPublisher(params) {
|
|
|
1661
1568
|
queue.splice(0, queue.length, ...controlFrames);
|
|
1662
1569
|
};
|
|
1663
1570
|
const waitForDrainWithinFinalizeGrace = async (pending) => {
|
|
1664
|
-
let timeout;
|
|
1665
1571
|
let drained = false;
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
timeout = setTimeout(resolve, CLICKCLACK_PROGRESS_FINALIZE_GRACE_MS);
|
|
1671
|
-
})]);
|
|
1672
|
-
return drained;
|
|
1673
|
-
} finally {
|
|
1674
|
-
if (timeout) clearTimeout(timeout);
|
|
1675
|
-
}
|
|
1572
|
+
await raceWithTimeout(pending.then(() => {
|
|
1573
|
+
drained = true;
|
|
1574
|
+
}), CLICKCLACK_PROGRESS_FINALIZE_GRACE_MS, () => void 0);
|
|
1575
|
+
return drained;
|
|
1676
1576
|
};
|
|
1677
1577
|
const scheduleLineDrain = () => {
|
|
1678
1578
|
if (lineDrainTimer) return;
|
|
@@ -9,10 +9,6 @@ const WebSocket = require(path.join(path.dirname(require.resolve("ws/package.jso
|
|
|
9
9
|
//#endregion
|
|
10
10
|
//#region extensions/clickclack/src/http-client.ts
|
|
11
11
|
/**
|
|
12
|
-
* Thin ClickClack REST/websocket client used by gateway, resolver, and outbound
|
|
13
|
-
* delivery code.
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
12
|
* Serializes optional provenance into the wire fields. Unknown JSON fields
|
|
17
13
|
* are ignored by servers without the provenance columns, so these are safe
|
|
18
14
|
* to send unconditionally when present.
|
|
@@ -60,9 +56,6 @@ function normalizeClickClackCorrelationId(value) {
|
|
|
60
56
|
if (!normalized || normalized.length > CLICKCLACK_CORRELATION_ID_MAX_LENGTH || !CLICKCLACK_CORRELATION_ID_PATTERN.test(normalized)) return;
|
|
61
57
|
return normalized;
|
|
62
58
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Creates a typed client for the ClickClack API using bearer-token auth.
|
|
65
|
-
*/
|
|
66
59
|
function createClickClackClient(options) {
|
|
67
60
|
const baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
68
61
|
const fetcher = options.fetch ?? fetch;
|
|
@@ -99,6 +92,9 @@ function createClickClackClient(options) {
|
|
|
99
92
|
if (timeout) clearTimeout(timeout);
|
|
100
93
|
}
|
|
101
94
|
}
|
|
95
|
+
async function requestObject(key, path, init) {
|
|
96
|
+
return (await request(path, init))[key];
|
|
97
|
+
}
|
|
102
98
|
async function fetchEventPage(workspaceId, pageOptions = {}) {
|
|
103
99
|
const query = new URLSearchParams({ workspace_id: workspaceId });
|
|
104
100
|
if (pageOptions.afterCursor) query.set("after_cursor", pageOptions.afterCursor);
|
|
@@ -111,7 +107,7 @@ function createClickClackClient(options) {
|
|
|
111
107
|
};
|
|
112
108
|
}
|
|
113
109
|
async function createMessage(path, body, opts) {
|
|
114
|
-
return (
|
|
110
|
+
return requestObject("message", path, {
|
|
115
111
|
method: "POST",
|
|
116
112
|
body: JSON.stringify({
|
|
117
113
|
body,
|
|
@@ -119,7 +115,7 @@ function createClickClackClient(options) {
|
|
|
119
115
|
...opts?.nonce ? { nonce: opts.nonce } : {},
|
|
120
116
|
...provenanceFields(opts?.provenance)
|
|
121
117
|
})
|
|
122
|
-
})
|
|
118
|
+
});
|
|
123
119
|
}
|
|
124
120
|
async function findByNonce(kind, params) {
|
|
125
121
|
const query = new URLSearchParams({
|
|
@@ -137,36 +133,22 @@ function createClickClackClient(options) {
|
|
|
137
133
|
}
|
|
138
134
|
}
|
|
139
135
|
return {
|
|
140
|
-
me: async () =>
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
},
|
|
155
|
-
|
|
156
|
-
return (await request(`/api/workspaces/${encodeURIComponent(workspaceId)}/channels`, {
|
|
157
|
-
method: "POST",
|
|
158
|
-
body: JSON.stringify(channel)
|
|
159
|
-
})).channel;
|
|
160
|
-
},
|
|
161
|
-
updateChannel: async (channelId, patch) => {
|
|
162
|
-
return (await request(`/api/channels/${encodeURIComponent(channelId)}`, {
|
|
163
|
-
method: "PATCH",
|
|
164
|
-
body: JSON.stringify(patch)
|
|
165
|
-
})).channel;
|
|
166
|
-
},
|
|
167
|
-
channelMessages: async (channelId, afterSeq, limit = 20) => {
|
|
168
|
-
return (await request(`/api/channels/${encodeURIComponent(channelId)}/messages?after_seq=${afterSeq}&limit=${limit}`)).messages;
|
|
169
|
-
},
|
|
136
|
+
me: async () => requestObject("user", "/api/me"),
|
|
137
|
+
setBotCommands: async (commands) => requestObject("bot_commands", "/api/bots/self/commands", {
|
|
138
|
+
method: "PUT",
|
|
139
|
+
body: JSON.stringify({ commands })
|
|
140
|
+
}),
|
|
141
|
+
workspaces: async () => requestObject("workspaces", "/api/workspaces"),
|
|
142
|
+
channels: async (workspaceId) => requestObject("channels", `/api/workspaces/${encodeURIComponent(workspaceId)}/channels`),
|
|
143
|
+
createChannel: async (workspaceId, channel) => requestObject("channel", `/api/workspaces/${encodeURIComponent(workspaceId)}/channels`, {
|
|
144
|
+
method: "POST",
|
|
145
|
+
body: JSON.stringify(channel)
|
|
146
|
+
}),
|
|
147
|
+
updateChannel: async (channelId, patch) => requestObject("channel", `/api/channels/${encodeURIComponent(channelId)}`, {
|
|
148
|
+
method: "PATCH",
|
|
149
|
+
body: JSON.stringify(patch)
|
|
150
|
+
}),
|
|
151
|
+
channelMessages: async (channelId, afterSeq, limit = 20) => requestObject("messages", `/api/channels/${encodeURIComponent(channelId)}/messages?after_seq=${afterSeq}&limit=${limit}`),
|
|
170
152
|
latestChannelMessages: async (channelId, limit = 30) => {
|
|
171
153
|
const boundedLimit = Math.max(1, Math.min(CLICKCLACK_MESSAGE_PAGE_LIMIT, limit));
|
|
172
154
|
let beforeSeq;
|
|
@@ -209,38 +191,32 @@ function createClickClackClient(options) {
|
|
|
209
191
|
beforeSeq = page.oldest_seq;
|
|
210
192
|
}
|
|
211
193
|
},
|
|
212
|
-
directMessages: async (conversationId, afterSeq, limit = 20) => {
|
|
213
|
-
return (await request(`/api/dms/${encodeURIComponent(conversationId)}/messages?after_seq=${afterSeq}&limit=${limit}`)).messages;
|
|
214
|
-
},
|
|
194
|
+
directMessages: async (conversationId, afterSeq, limit = 20) => requestObject("messages", `/api/dms/${encodeURIComponent(conversationId)}/messages?after_seq=${afterSeq}&limit=${limit}`),
|
|
215
195
|
thread: async (messageId) => await request(`/api/messages/${encodeURIComponent(messageId)}/thread`),
|
|
216
|
-
message: async (messageId) => {
|
|
217
|
-
return (await request(`/api/messages/${encodeURIComponent(messageId)}`)).message;
|
|
218
|
-
},
|
|
196
|
+
message: async (messageId) => requestObject("message", `/api/messages/${encodeURIComponent(messageId)}`),
|
|
219
197
|
findMessageByNonce: async (params) => findByNonce("message", params),
|
|
220
198
|
createChannelMessage: async (channelId, body, opts) => createMessage(`/api/channels/${encodeURIComponent(channelId)}/messages`, body, opts),
|
|
221
199
|
createThreadReply: async (messageId, body, opts) => createMessage(`/api/messages/${encodeURIComponent(messageId)}/thread/replies`, body, {
|
|
222
200
|
nonce: opts?.nonce,
|
|
223
201
|
provenance: opts?.provenance
|
|
224
202
|
}),
|
|
225
|
-
createDirectConversation: async (workspaceId, memberIds) => {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
})).conversation;
|
|
233
|
-
},
|
|
203
|
+
createDirectConversation: async (workspaceId, memberIds) => requestObject("conversation", "/api/dms", {
|
|
204
|
+
method: "POST",
|
|
205
|
+
body: JSON.stringify({
|
|
206
|
+
workspace_id: workspaceId,
|
|
207
|
+
member_ids: memberIds
|
|
208
|
+
})
|
|
209
|
+
}),
|
|
234
210
|
createUpload: async (params) => {
|
|
235
211
|
const form = new FormData();
|
|
236
212
|
const bytes = bufferToBlobPart(params.buffer);
|
|
237
213
|
form.append("file", new Blob([bytes], { type: params.contentType }), params.filename);
|
|
238
214
|
const query = new URLSearchParams({ workspace_id: params.workspaceId });
|
|
239
215
|
if (params.nonce) query.set("nonce", params.nonce);
|
|
240
|
-
return (
|
|
216
|
+
return requestObject("upload", `/api/uploads?${query.toString()}`, {
|
|
241
217
|
method: "POST",
|
|
242
218
|
body: form
|
|
243
|
-
})
|
|
219
|
+
});
|
|
244
220
|
},
|
|
245
221
|
findUploadByNonce: async (params) => findByNonce("upload", params),
|
|
246
222
|
attachUpload: async (messageId, uploadId) => {
|
|
@@ -256,7 +232,7 @@ function createClickClackClient(options) {
|
|
|
256
232
|
*/
|
|
257
233
|
createActivityMessage: async (params) => {
|
|
258
234
|
if (!params.channelId && !params.conversationId) throw new Error("createActivityMessage requires a channelId or conversationId");
|
|
259
|
-
return (
|
|
235
|
+
return requestObject("message", params.channelId ? `/api/channels/${encodeURIComponent(params.channelId)}/messages` : `/api/dms/${encodeURIComponent(params.conversationId ?? "")}/messages`, {
|
|
260
236
|
method: "POST",
|
|
261
237
|
body: JSON.stringify({
|
|
262
238
|
body: params.body,
|
|
@@ -264,15 +240,12 @@ function createClickClackClient(options) {
|
|
|
264
240
|
turn_id: params.turnId,
|
|
265
241
|
...provenanceFields(params.provenance)
|
|
266
242
|
})
|
|
267
|
-
})
|
|
268
|
-
},
|
|
269
|
-
/** PATCHes the body of an existing message (activity row coalescing). */
|
|
270
|
-
updateMessageBody: async (messageId, body) => {
|
|
271
|
-
return (await request(`/api/messages/${encodeURIComponent(messageId)}`, {
|
|
272
|
-
method: "PATCH",
|
|
273
|
-
body: JSON.stringify({ body })
|
|
274
|
-
})).message;
|
|
243
|
+
});
|
|
275
244
|
},
|
|
245
|
+
updateMessageBody: async (messageId, body) => requestObject("message", `/api/messages/${encodeURIComponent(messageId)}`, {
|
|
246
|
+
method: "PATCH",
|
|
247
|
+
body: JSON.stringify({ body })
|
|
248
|
+
}),
|
|
276
249
|
/**
|
|
277
250
|
* Publishes an ephemeral realtime signal such as native agent progress.
|
|
278
251
|
* These frames are intentionally not persisted as messages.
|
|
@@ -313,19 +286,15 @@ function createClickClackClient(options) {
|
|
|
313
286
|
}
|
|
314
287
|
//#endregion
|
|
315
288
|
//#region extensions/clickclack/src/resolve.ts
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
289
|
+
function findClickClackWorkspace(workspaces, selector) {
|
|
290
|
+
return workspaces.find((candidate) => candidate.id === selector || candidate.slug === selector || candidate.name === selector);
|
|
291
|
+
}
|
|
319
292
|
async function resolveWorkspaceId(client, workspace) {
|
|
320
293
|
if (workspace.startsWith("wsp_")) return workspace;
|
|
321
|
-
const found = (await client.workspaces()
|
|
294
|
+
const found = findClickClackWorkspace(await client.workspaces(), workspace);
|
|
322
295
|
if (!found) throw new Error(`ClickClack workspace not found: ${workspace}`);
|
|
323
296
|
return found.id;
|
|
324
297
|
}
|
|
325
|
-
/**
|
|
326
|
-
* Resolves a channel name/id from config or target input to a ClickClack
|
|
327
|
-
* channel id.
|
|
328
|
-
*/
|
|
329
298
|
async function resolveChannelId(client, workspaceId, channel) {
|
|
330
299
|
if (channel.startsWith("chn_")) return channel;
|
|
331
300
|
const found = (await client.channels(workspaceId)).find((candidate) => candidate.id === channel || candidate.name === channel);
|
|
@@ -333,4 +302,4 @@ async function resolveChannelId(client, workspaceId, channel) {
|
|
|
333
302
|
return found.id;
|
|
334
303
|
}
|
|
335
304
|
//#endregion
|
|
336
|
-
export {
|
|
305
|
+
export { createClickClackClient as a, ClickClackHttpError as i, resolveChannelId as n, isClickClackChannelNameConflict as o, resolveWorkspaceId as r, normalizeClickClackCorrelationId as s, findClickClackWorkspace as t };
|