@openclaw/clickclack 2026.7.2-beta.1 → 2026.7.2-beta.3
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 +27 -0
- package/dist/api.js +2 -1
- package/dist/{channel-Ds6d_3nx.js → channel-CEYthZ9N.js} +169 -463
- package/dist/channel-plugin-api.js +1 -1
- package/dist/runtime-api.js +2 -1
- package/dist/secret-contract-BKkzzjBA.js +35 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/setup-claim-BUWvZjtu.js +114 -0
- package/dist/setup-entry.js +15 -0
- package/dist/setup-plugin-api.js +18 -0
- package/dist/setup-surface-CNjp76Xx.js +911 -0
- package/npm-shrinkwrap.json +3 -3
- package/openclaw.plugin.json +12 -0
- package/package.json +18 -6
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as clickClackPlugin } from "./channel-
|
|
1
|
+
import { t as clickClackPlugin } from "./channel-CEYthZ9N.js";
|
|
2
2
|
export { clickClackPlugin };
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as createClickClackClient, m as resolveClickClackAccount } from "./setup-surface-CNjp76Xx.js";
|
|
2
|
+
import { a as setClickClackRuntime, r as parseClickClackTarget } from "./channel-CEYthZ9N.js";
|
|
2
3
|
import "./api.js";
|
|
3
4
|
export { createClickClackClient, parseClickClackTarget, resolveClickClackAccount, setClickClackRuntime };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
|
+
import { collectConditionalChannelFieldAssignments, createChannelSecretTargetRegistryEntries, getChannelSurface, hasConfiguredSecretInputValue } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
3
|
+
//#region extensions/clickclack/src/secret-contract.ts
|
|
4
|
+
const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
|
|
5
|
+
channelKey: "clickclack",
|
|
6
|
+
account: ["token"],
|
|
7
|
+
channel: ["token"]
|
|
8
|
+
});
|
|
9
|
+
function collectRuntimeConfigAssignments(params) {
|
|
10
|
+
const resolved = getChannelSurface(params.config, "clickclack");
|
|
11
|
+
if (!resolved) return;
|
|
12
|
+
const { channel: clickclack, surface } = resolved;
|
|
13
|
+
const baseTokenFile = normalizeOptionalString(clickclack.tokenFile) ?? "";
|
|
14
|
+
const accountTokenFile = (account) => normalizeOptionalString(account.tokenFile) ?? "";
|
|
15
|
+
const hasImplicitDefault = Boolean(normalizeOptionalString(clickclack.baseUrl)) && Boolean(normalizeOptionalString(clickclack.workspace));
|
|
16
|
+
collectConditionalChannelFieldAssignments({
|
|
17
|
+
channelKey: "clickclack",
|
|
18
|
+
field: "token",
|
|
19
|
+
channel: clickclack,
|
|
20
|
+
surface,
|
|
21
|
+
defaults: params.defaults,
|
|
22
|
+
context: params.context,
|
|
23
|
+
topLevelActiveWithoutAccounts: baseTokenFile.length === 0,
|
|
24
|
+
topLevelInheritedAccountActive: ({ account, enabled }) => hasImplicitDefault && baseTokenFile.length === 0 || enabled && baseTokenFile.length === 0 && accountTokenFile(account).length === 0 && !hasConfiguredSecretInputValue(account.token, params.defaults),
|
|
25
|
+
accountActive: ({ account, enabled }) => enabled && accountTokenFile(account).length === 0,
|
|
26
|
+
topInactiveReason: "no enabled ClickClack account inherits this top-level token (tokenFile is configured).",
|
|
27
|
+
accountInactiveReason: "ClickClack account is disabled or tokenFile is configured."
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const channelSecrets = {
|
|
31
|
+
secretTargetRegistryEntries,
|
|
32
|
+
collectRuntimeConfigAssignments
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { createProviderOperationDeadline, readProviderJsonResponse, readResponseTextLimited, resolveProviderOperationTimeoutMs } from "openclaw/plugin-sdk/provider-http";
|
|
2
|
+
import { fetchWithSsrFGuard, isPrivateOrLoopbackHost, resolvePinnedHostnameWithPolicy, ssrfPolicyFromHttpBaseUrlAllowedHostname } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
3
|
+
import { withTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
4
|
+
//#region extensions/clickclack/src/setup-claim.ts
|
|
5
|
+
const CLICKCLACK_ERROR_BODY_LIMIT_BYTES = 8 * 1024;
|
|
6
|
+
const CLICKCLACK_SETUP_CODE_CLAIM_JSON_LIMIT_BYTES = 64 * 1024;
|
|
7
|
+
const CLICKCLACK_SETUP_CODE_CLAIM_TIMEOUT_MS = 3e4;
|
|
8
|
+
var ClickClackSetupCodeClaimError = class extends Error {
|
|
9
|
+
constructor(status, detail) {
|
|
10
|
+
super(`ClickClack setup code claim failed (${status}): ${detail}`);
|
|
11
|
+
this.status = status;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function requireRecord(value, label) {
|
|
15
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`ClickClack setup code claim returned invalid ${label}`);
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
function requireString(record, key, label) {
|
|
19
|
+
const value = record[key];
|
|
20
|
+
if (typeof value !== "string" || !value.trim()) throw new Error(`ClickClack setup code claim returned invalid ${label}.${key}`);
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function parseClickClackSetupCodeClaim(value) {
|
|
24
|
+
const claim = requireRecord(value, "response");
|
|
25
|
+
const bot = requireRecord(claim.bot, "bot");
|
|
26
|
+
const workspace = requireRecord(claim.workspace, "workspace");
|
|
27
|
+
const defaults = requireRecord(claim.defaults, "defaults");
|
|
28
|
+
const defaultTo = defaults.defaultTo;
|
|
29
|
+
const allowFrom = defaults.allowFrom;
|
|
30
|
+
const agentActivity = defaults.agentActivity;
|
|
31
|
+
if (defaultTo !== void 0 && typeof defaultTo !== "string") throw new Error("ClickClack setup code claim returned invalid defaults.defaultTo");
|
|
32
|
+
if (allowFrom !== void 0 && (!Array.isArray(allowFrom) || !allowFrom.every((entry) => typeof entry === "string"))) throw new Error("ClickClack setup code claim returned invalid defaults.allowFrom");
|
|
33
|
+
if (agentActivity !== void 0 && typeof agentActivity !== "boolean") throw new Error("ClickClack setup code claim returned invalid defaults.agentActivity");
|
|
34
|
+
return {
|
|
35
|
+
token: requireString(claim, "token", "response"),
|
|
36
|
+
bot: {
|
|
37
|
+
id: requireString(bot, "id", "bot"),
|
|
38
|
+
handle: requireString(bot, "handle", "bot"),
|
|
39
|
+
display_name: requireString(bot, "display_name", "bot")
|
|
40
|
+
},
|
|
41
|
+
workspace: {
|
|
42
|
+
id: requireString(workspace, "id", "workspace"),
|
|
43
|
+
route_id: requireString(workspace, "route_id", "workspace"),
|
|
44
|
+
slug: requireString(workspace, "slug", "workspace"),
|
|
45
|
+
name: requireString(workspace, "name", "workspace")
|
|
46
|
+
},
|
|
47
|
+
defaults: {
|
|
48
|
+
...defaultTo !== void 0 ? { defaultTo } : {},
|
|
49
|
+
...allowFrom !== void 0 ? { allowFrom } : {},
|
|
50
|
+
...agentActivity !== void 0 ? { agentActivity } : {}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Claims a one-time setup code without sending any existing bot credential. */
|
|
55
|
+
async function claimClickClackSetupCode(params) {
|
|
56
|
+
const baseUrl = params.baseUrl.replace(/\/+$/, "");
|
|
57
|
+
const parsedBaseUrl = new URL(baseUrl);
|
|
58
|
+
const deadline = createProviderOperationDeadline({
|
|
59
|
+
label: "ClickClack setup code claim",
|
|
60
|
+
timeoutMs: CLICKCLACK_SETUP_CODE_CLAIM_TIMEOUT_MS
|
|
61
|
+
});
|
|
62
|
+
let pinnedHttpTarget;
|
|
63
|
+
if (parsedBaseUrl.protocol === "http:") {
|
|
64
|
+
const resolveTimeoutMs = resolveProviderOperationTimeoutMs({
|
|
65
|
+
deadline,
|
|
66
|
+
defaultTimeoutMs: CLICKCLACK_SETUP_CODE_CLAIM_TIMEOUT_MS
|
|
67
|
+
});
|
|
68
|
+
const pinned = await withTimeout(resolvePinnedHostnameWithPolicy(parsedBaseUrl.hostname, {
|
|
69
|
+
lookupFn: params.lookupFn,
|
|
70
|
+
policy: { dangerouslyAllowPrivateNetwork: true }
|
|
71
|
+
}), resolveTimeoutMs, { message: `ClickClack setup code claim timed out after ${CLICKCLACK_SETUP_CODE_CLAIM_TIMEOUT_MS}ms` });
|
|
72
|
+
if (!pinned.addresses.every((address) => isPrivateOrLoopbackHost(address))) throw new Error("ClickClack setup codes require HTTPS unless the server is on a private or loopback network.");
|
|
73
|
+
pinnedHttpTarget = {
|
|
74
|
+
hostname: pinned.hostname,
|
|
75
|
+
addresses: pinned.addresses
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const { response, release } = await fetchWithSsrFGuard({
|
|
79
|
+
url: `${baseUrl}/api/bot-setup-codes/claim`,
|
|
80
|
+
fetchImpl: params.fetch,
|
|
81
|
+
init: {
|
|
82
|
+
method: "POST",
|
|
83
|
+
headers: {
|
|
84
|
+
Accept: "application/json",
|
|
85
|
+
"Content-Type": "application/json"
|
|
86
|
+
},
|
|
87
|
+
body: JSON.stringify({ code: params.code })
|
|
88
|
+
},
|
|
89
|
+
maxRedirects: 0,
|
|
90
|
+
timeoutMs: resolveProviderOperationTimeoutMs({
|
|
91
|
+
deadline,
|
|
92
|
+
defaultTimeoutMs: CLICKCLACK_SETUP_CODE_CLAIM_TIMEOUT_MS
|
|
93
|
+
}),
|
|
94
|
+
requireHttps: parsedBaseUrl.protocol === "https:",
|
|
95
|
+
policy: ssrfPolicyFromHttpBaseUrlAllowedHostname(baseUrl),
|
|
96
|
+
lookupFn: params.lookupFn,
|
|
97
|
+
...pinnedHttpTarget ? { dispatcherPolicy: {
|
|
98
|
+
mode: "direct",
|
|
99
|
+
pinnedHostname: pinnedHttpTarget
|
|
100
|
+
} } : {},
|
|
101
|
+
auditContext: "ClickClack setup code claim"
|
|
102
|
+
});
|
|
103
|
+
try {
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
const detail = await readResponseTextLimited(response, CLICKCLACK_ERROR_BODY_LIMIT_BYTES);
|
|
106
|
+
throw new ClickClackSetupCodeClaimError(response.status, detail);
|
|
107
|
+
}
|
|
108
|
+
return parseClickClackSetupCodeClaim(await readProviderJsonResponse(response, "ClickClack setup code claim", { maxBytes: CLICKCLACK_SETUP_CODE_CLAIM_JSON_LIMIT_BYTES }));
|
|
109
|
+
} finally {
|
|
110
|
+
await release();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
export { claimClickClackSetupCode };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entry-contract";
|
|
2
|
+
//#region extensions/clickclack/setup-entry.ts
|
|
3
|
+
var setup_entry_default = defineBundledChannelSetupEntry({
|
|
4
|
+
importMetaUrl: import.meta.url,
|
|
5
|
+
plugin: {
|
|
6
|
+
specifier: "./setup-plugin-api.js",
|
|
7
|
+
exportName: "clickClackSetupPlugin"
|
|
8
|
+
},
|
|
9
|
+
secrets: {
|
|
10
|
+
specifier: "./secret-contract-api.js",
|
|
11
|
+
exportName: "channelSecrets"
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
//#endregion
|
|
15
|
+
export { setup_entry_default as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { l as clickClackConfigAdapter, n as clickClackSetupAdapter, s as clickClackConfigSchema, t as clickClackSetupWizard, u as clickClackMeta } from "./setup-surface-CNjp76Xx.js";
|
|
2
|
+
//#region extensions/clickclack/src/channel.setup.ts
|
|
3
|
+
const clickClackSetupPlugin = {
|
|
4
|
+
id: "clickclack",
|
|
5
|
+
meta: clickClackMeta,
|
|
6
|
+
capabilities: {
|
|
7
|
+
chatTypes: ["direct", "group"],
|
|
8
|
+
threads: true,
|
|
9
|
+
blockStreaming: true
|
|
10
|
+
},
|
|
11
|
+
reload: { configPrefixes: ["channels.clickclack"] },
|
|
12
|
+
configSchema: clickClackConfigSchema,
|
|
13
|
+
config: clickClackConfigAdapter,
|
|
14
|
+
setup: clickClackSetupAdapter,
|
|
15
|
+
setupWizard: clickClackSetupWizard
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { clickClackSetupPlugin };
|