cclawd 1.0.2 → 1.0.4
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/build-info.json +3 -3
- package/dist/plugin-sdk/active-listener-CN-tMEvN.js +35 -0
- package/dist/plugin-sdk/api-key-rotation-CimGYMBc.js +176 -0
- package/dist/plugin-sdk/audio-preflight-C-xXBoE2.js +51 -0
- package/dist/plugin-sdk/audio-transcription-runner-CTIHpebA.js +2173 -0
- package/dist/plugin-sdk/audit-membership-runtime-BFatB2LJ.js +58 -0
- package/dist/plugin-sdk/channel-activity-DO0FEzyj.js +95 -0
- package/dist/plugin-sdk/channel-web-Da-__nUF.js +2238 -0
- package/dist/plugin-sdk/commands-registry-6no2NNrY.js +1118 -0
- package/dist/plugin-sdk/compact.runtime-CCoclu5e.js +35 -0
- package/dist/plugin-sdk/config-B9ODwgpz.js +37426 -0
- package/dist/plugin-sdk/deliver-B1fFpKjV.js +1757 -0
- package/dist/plugin-sdk/deliver-runtime-DB-VRMe1.js +15 -0
- package/dist/plugin-sdk/deps-send-discord.runtime-DklqycYG.js +15 -0
- package/dist/plugin-sdk/deps-send-imessage.runtime-Chs8zeon.js +14 -0
- package/dist/plugin-sdk/deps-send-signal.runtime-clW9aSJP.js +13 -0
- package/dist/plugin-sdk/deps-send-slack.runtime-BUx0LYY1.js +13 -0
- package/dist/plugin-sdk/deps-send-telegram.runtime-LECSHgMG.js +16 -0
- package/dist/plugin-sdk/deps-send-whatsapp.runtime-D2d65fw0.js +40 -0
- package/dist/plugin-sdk/diagnostic-CxIvS-C2.js +315 -0
- package/dist/plugin-sdk/dispatch-BqlR4dPx.js +105863 -0
- package/dist/plugin-sdk/env-b9k1PHMI.js +34 -0
- package/dist/plugin-sdk/fetch-PoxzAANT.js +326 -0
- package/dist/plugin-sdk/fetch-guard-4UVSZ0uS.js +164 -0
- package/dist/plugin-sdk/image-Ch6M4tnJ.js +2420 -0
- package/dist/plugin-sdk/image-runtime-CSh2o5wY.js +8 -0
- package/dist/plugin-sdk/index.js +35 -35
- package/dist/plugin-sdk/ir-CugsqGH8.js +1312 -0
- package/dist/plugin-sdk/local-roots-adnEg9zb.js +217 -0
- package/dist/plugin-sdk/logger-D6zRubj0.js +1164 -0
- package/dist/plugin-sdk/login-CYvkQ0At.js +54 -0
- package/dist/plugin-sdk/login-qr-ll4NtaT5.js +316 -0
- package/dist/plugin-sdk/manager-CHy8IclH.js +3959 -0
- package/dist/plugin-sdk/manager-runtime-C70EkEr7.js +11 -0
- package/dist/plugin-sdk/outbound-Wzs2iN7X.js +216 -0
- package/dist/plugin-sdk/outbound-attachment-khXJwucX.js +17 -0
- package/dist/plugin-sdk/paths-BtVqCdw4.js +3063 -0
- package/dist/plugin-sdk/pi-model-discovery-Dh4ziodY.js +131 -0
- package/dist/plugin-sdk/pi-model-discovery-runtime-b83Xe-HT.js +8 -0
- package/dist/plugin-sdk/pi-tools.before-tool-call.runtime-C1z5CDBF.js +349 -0
- package/dist/plugin-sdk/proxy-fetch-CJEmoBxi.js +54 -0
- package/dist/plugin-sdk/pw-ai-Dj3Cvlzl.js +1990 -0
- package/dist/plugin-sdk/qmd-manager-egHUAseQ.js +1581 -0
- package/dist/plugin-sdk/resolve-outbound-target-BiICvIKs.js +38 -0
- package/dist/plugin-sdk/runtime-whatsapp-login.runtime-DNApufzW.js +9 -0
- package/dist/plugin-sdk/runtime-whatsapp-outbound.runtime-CBmtfIQ8.js +13 -0
- package/dist/plugin-sdk/send-CScblaI4.js +532 -0
- package/dist/plugin-sdk/send-CeHhnld6.js +407 -0
- package/dist/plugin-sdk/send-DP_c8JfR.js +3277 -0
- package/dist/plugin-sdk/send-Dc5fI6e8.js +495 -0
- package/dist/plugin-sdk/send-l-77_s1_.js +2507 -0
- package/dist/plugin-sdk/session-CkOKZaqa.js +166 -0
- package/dist/plugin-sdk/signal.js +2 -2
- package/dist/plugin-sdk/skill-commands-BohYCgkq.js +336 -0
- package/dist/plugin-sdk/slash-commands.runtime-DpLfVTM6.js +8 -0
- package/dist/plugin-sdk/slash-dispatch.runtime-CASMHwpm.js +35 -0
- package/dist/plugin-sdk/slash-skill-commands.runtime-D7rrJEci.js +9 -0
- package/dist/plugin-sdk/sqlite-CJE3X7Mv.js +1005 -0
- package/dist/plugin-sdk/subagent-registry-runtime-B1oo5bih.js +35 -0
- package/dist/plugin-sdk/tables-D5VgpTmm.js +53 -0
- package/dist/plugin-sdk/target-errors-C6zZ_OpA.js +191 -0
- package/dist/plugin-sdk/tokens-DUnJnpMS.js +50 -0
- package/dist/plugin-sdk/web-TfUM1nSi.js +39 -0
- package/dist/plugin-sdk/whatsapp-actions-DuWJ0j1r.js +71 -0
- package/extensions/mfa-auth/index.ts +36 -17
- package/extensions/mfa-auth/src/auth-manager.ts +4 -0
- package/extensions/mfa-auth/src/notification-service.ts +5 -1
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import "./paths-BtVqCdw4.js";
|
|
2
|
+
import "./config-B9ODwgpz.js";
|
|
3
|
+
import { a as countPendingDescendantRuns, c as listSubagentRunsForRequester, d as shouldIgnorePostCompletionAnnounceForSession, i as countActiveDescendantRuns, l as replaceSubagentRunAfterSteer, o as countPendingDescendantRunsExcludingRun, s as isSubagentSessionRunActive, u as resolveRequesterForChildSession } from "./dispatch-BqlR4dPx.js";
|
|
4
|
+
import "./paths-eFexkPEh.js";
|
|
5
|
+
import "./github-copilot-token-Cxf8QYZb.js";
|
|
6
|
+
import "./logger-D6zRubj0.js";
|
|
7
|
+
import "./env-b9k1PHMI.js";
|
|
8
|
+
import "./send-DP_c8JfR.js";
|
|
9
|
+
import "./fetch-BSKpf2dM.js";
|
|
10
|
+
import "./channel-activity-DO0FEzyj.js";
|
|
11
|
+
import "./fetch-guard-4UVSZ0uS.js";
|
|
12
|
+
import "./local-roots-adnEg9zb.js";
|
|
13
|
+
import "./ir-CugsqGH8.js";
|
|
14
|
+
import "./render-CKf6NJ1M.js";
|
|
15
|
+
import "./tables-D5VgpTmm.js";
|
|
16
|
+
import "./send-l-77_s1_.js";
|
|
17
|
+
import "./target-errors-C6zZ_OpA.js";
|
|
18
|
+
import "./send-CeHhnld6.js";
|
|
19
|
+
import "./deliver-B1fFpKjV.js";
|
|
20
|
+
import "./diagnostic-CxIvS-C2.js";
|
|
21
|
+
import "./pi-model-discovery-Dh4ziodY.js";
|
|
22
|
+
import "./audio-transcription-runner-CTIHpebA.js";
|
|
23
|
+
import "./image-Ch6M4tnJ.js";
|
|
24
|
+
import "./api-key-rotation-CimGYMBc.js";
|
|
25
|
+
import "./proxy-fetch-CJEmoBxi.js";
|
|
26
|
+
import "./tokens-DUnJnpMS.js";
|
|
27
|
+
import "./commands-registry-6no2NNrY.js";
|
|
28
|
+
import "./skill-commands-BohYCgkq.js";
|
|
29
|
+
import "./send-CScblaI4.js";
|
|
30
|
+
import "./outbound-attachment-khXJwucX.js";
|
|
31
|
+
import "./send-Dc5fI6e8.js";
|
|
32
|
+
import "./sqlite-CJE3X7Mv.js";
|
|
33
|
+
import "./fetch-PoxzAANT.js";
|
|
34
|
+
import "./manager-CHy8IclH.js";
|
|
35
|
+
export { countActiveDescendantRuns, countPendingDescendantRuns, countPendingDescendantRunsExcludingRun, isSubagentSessionRunActive, listSubagentRunsForRequester, replaceSubagentRunAfterSteer, resolveRequesterForChildSession, shouldIgnorePostCompletionAnnounceForSession };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { r as markdownToIRWithMeta } from "./ir-CugsqGH8.js";
|
|
2
|
+
import { t as renderMarkdownWithMarkers } from "./render-CKf6NJ1M.js";
|
|
3
|
+
//#region src/markdown/tables.ts
|
|
4
|
+
const MARKDOWN_STYLE_MARKERS = {
|
|
5
|
+
bold: {
|
|
6
|
+
open: "**",
|
|
7
|
+
close: "**"
|
|
8
|
+
},
|
|
9
|
+
italic: {
|
|
10
|
+
open: "_",
|
|
11
|
+
close: "_"
|
|
12
|
+
},
|
|
13
|
+
strikethrough: {
|
|
14
|
+
open: "~~",
|
|
15
|
+
close: "~~"
|
|
16
|
+
},
|
|
17
|
+
code: {
|
|
18
|
+
open: "`",
|
|
19
|
+
close: "`"
|
|
20
|
+
},
|
|
21
|
+
code_block: {
|
|
22
|
+
open: "```\n",
|
|
23
|
+
close: "```"
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
function convertMarkdownTables(markdown, mode) {
|
|
27
|
+
if (!markdown || mode === "off") return markdown;
|
|
28
|
+
const { ir, hasTables } = markdownToIRWithMeta(markdown, {
|
|
29
|
+
linkify: false,
|
|
30
|
+
autolink: false,
|
|
31
|
+
headingStyle: "none",
|
|
32
|
+
blockquotePrefix: "",
|
|
33
|
+
tableMode: mode
|
|
34
|
+
});
|
|
35
|
+
if (!hasTables) return markdown;
|
|
36
|
+
return renderMarkdownWithMarkers(ir, {
|
|
37
|
+
styleMarkers: MARKDOWN_STYLE_MARKERS,
|
|
38
|
+
escapeText: (text) => text,
|
|
39
|
+
buildLink: (link, text) => {
|
|
40
|
+
const href = link.href.trim();
|
|
41
|
+
if (!href) return null;
|
|
42
|
+
if (!text.slice(link.start, link.end)) return null;
|
|
43
|
+
return {
|
|
44
|
+
start: link.start,
|
|
45
|
+
end: link.end,
|
|
46
|
+
open: "[",
|
|
47
|
+
close: `](${href})`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { convertMarkdownTables as t };
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { Ts as detectMime, Vn as sanitizeToolResultImages } from "./config-B9ODwgpz.js";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
//#region src/agents/tools/common.ts
|
|
4
|
+
var ToolInputError = class extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.status = 400;
|
|
8
|
+
this.name = "ToolInputError";
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var ToolAuthorizationError = class extends ToolInputError {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.status = 403;
|
|
15
|
+
this.name = "ToolAuthorizationError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
function createActionGate(actions) {
|
|
19
|
+
return (key, defaultValue = true) => {
|
|
20
|
+
const value = actions?.[key];
|
|
21
|
+
if (value === void 0) return defaultValue;
|
|
22
|
+
return value !== false;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function toSnakeCaseKey(key) {
|
|
26
|
+
return key.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
27
|
+
}
|
|
28
|
+
function readParamRaw(params, key) {
|
|
29
|
+
if (Object.hasOwn(params, key)) return params[key];
|
|
30
|
+
const snakeKey = toSnakeCaseKey(key);
|
|
31
|
+
if (snakeKey !== key && Object.hasOwn(params, snakeKey)) return params[snakeKey];
|
|
32
|
+
}
|
|
33
|
+
function readStringParam(params, key, options = {}) {
|
|
34
|
+
const { required = false, trim = true, label = key, allowEmpty = false } = options;
|
|
35
|
+
const raw = readParamRaw(params, key);
|
|
36
|
+
if (typeof raw !== "string") {
|
|
37
|
+
if (required) throw new ToolInputError(`${label} required`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const value = trim ? raw.trim() : raw;
|
|
41
|
+
if (!value && !allowEmpty) {
|
|
42
|
+
if (required) throw new ToolInputError(`${label} required`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
function readStringOrNumberParam(params, key, options = {}) {
|
|
48
|
+
const { required = false, label = key } = options;
|
|
49
|
+
const raw = readParamRaw(params, key);
|
|
50
|
+
if (typeof raw === "number" && Number.isFinite(raw)) return String(raw);
|
|
51
|
+
if (typeof raw === "string") {
|
|
52
|
+
const value = raw.trim();
|
|
53
|
+
if (value) return value;
|
|
54
|
+
}
|
|
55
|
+
if (required) throw new ToolInputError(`${label} required`);
|
|
56
|
+
}
|
|
57
|
+
function readNumberParam(params, key, options = {}) {
|
|
58
|
+
const { required = false, label = key, integer = false, strict = false } = options;
|
|
59
|
+
const raw = readParamRaw(params, key);
|
|
60
|
+
let value;
|
|
61
|
+
if (typeof raw === "number" && Number.isFinite(raw)) value = raw;
|
|
62
|
+
else if (typeof raw === "string") {
|
|
63
|
+
const trimmed = raw.trim();
|
|
64
|
+
if (trimmed) {
|
|
65
|
+
const parsed = strict ? Number(trimmed) : Number.parseFloat(trimmed);
|
|
66
|
+
if (Number.isFinite(parsed)) value = parsed;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (value === void 0) {
|
|
70
|
+
if (required) throw new ToolInputError(`${label} required`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
return integer ? Math.trunc(value) : value;
|
|
74
|
+
}
|
|
75
|
+
function readStringArrayParam(params, key, options = {}) {
|
|
76
|
+
const { required = false, label = key } = options;
|
|
77
|
+
const raw = readParamRaw(params, key);
|
|
78
|
+
if (Array.isArray(raw)) {
|
|
79
|
+
const values = raw.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean);
|
|
80
|
+
if (values.length === 0) {
|
|
81
|
+
if (required) throw new ToolInputError(`${label} required`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
return values;
|
|
85
|
+
}
|
|
86
|
+
if (typeof raw === "string") {
|
|
87
|
+
const value = raw.trim();
|
|
88
|
+
if (!value) {
|
|
89
|
+
if (required) throw new ToolInputError(`${label} required`);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
return [value];
|
|
93
|
+
}
|
|
94
|
+
if (required) throw new ToolInputError(`${label} required`);
|
|
95
|
+
}
|
|
96
|
+
function readReactionParams(params, options) {
|
|
97
|
+
const emojiKey = options.emojiKey ?? "emoji";
|
|
98
|
+
const removeKey = options.removeKey ?? "remove";
|
|
99
|
+
const remove = typeof params[removeKey] === "boolean" ? params[removeKey] : false;
|
|
100
|
+
const emoji = readStringParam(params, emojiKey, {
|
|
101
|
+
required: true,
|
|
102
|
+
allowEmpty: true
|
|
103
|
+
});
|
|
104
|
+
if (remove && !emoji) throw new ToolInputError(options.removeErrorMessage);
|
|
105
|
+
return {
|
|
106
|
+
emoji,
|
|
107
|
+
remove,
|
|
108
|
+
isEmpty: !emoji
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function jsonResult(payload) {
|
|
112
|
+
return {
|
|
113
|
+
content: [{
|
|
114
|
+
type: "text",
|
|
115
|
+
text: JSON.stringify(payload, null, 2)
|
|
116
|
+
}],
|
|
117
|
+
details: payload
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async function imageResult(params) {
|
|
121
|
+
return await sanitizeToolResultImages({
|
|
122
|
+
content: [{
|
|
123
|
+
type: "text",
|
|
124
|
+
text: params.extraText ?? `MEDIA:${params.path}`
|
|
125
|
+
}, {
|
|
126
|
+
type: "image",
|
|
127
|
+
data: params.base64,
|
|
128
|
+
mimeType: params.mimeType
|
|
129
|
+
}],
|
|
130
|
+
details: {
|
|
131
|
+
path: params.path,
|
|
132
|
+
...params.details
|
|
133
|
+
}
|
|
134
|
+
}, params.label, params.imageSanitization);
|
|
135
|
+
}
|
|
136
|
+
async function imageResultFromFile(params) {
|
|
137
|
+
const buf = await fs.readFile(params.path);
|
|
138
|
+
const mimeType = await detectMime({ buffer: buf.slice(0, 256) }) ?? "image/png";
|
|
139
|
+
return await imageResult({
|
|
140
|
+
label: params.label,
|
|
141
|
+
path: params.path,
|
|
142
|
+
base64: buf.toString("base64"),
|
|
143
|
+
mimeType,
|
|
144
|
+
extraText: params.extraText,
|
|
145
|
+
details: params.details,
|
|
146
|
+
imageSanitization: params.imageSanitization
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Validate and parse an `availableTags` parameter from untrusted input.
|
|
151
|
+
* Returns `undefined` when the value is missing or not an array.
|
|
152
|
+
* Entries that lack a string `name` are silently dropped.
|
|
153
|
+
*/
|
|
154
|
+
function parseAvailableTags(raw) {
|
|
155
|
+
if (raw === void 0 || raw === null) return;
|
|
156
|
+
if (!Array.isArray(raw)) return;
|
|
157
|
+
const result = raw.filter((t) => typeof t === "object" && t !== null && typeof t.name === "string").map((t) => ({
|
|
158
|
+
...t.id !== void 0 && typeof t.id === "string" ? { id: t.id } : {},
|
|
159
|
+
name: t.name,
|
|
160
|
+
...typeof t.moderated === "boolean" ? { moderated: t.moderated } : {},
|
|
161
|
+
...t.emoji_id === null || typeof t.emoji_id === "string" ? { emoji_id: t.emoji_id } : {},
|
|
162
|
+
...t.emoji_name === null || typeof t.emoji_name === "string" ? { emoji_name: t.emoji_name } : {}
|
|
163
|
+
}));
|
|
164
|
+
return result.length ? result : void 0;
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/infra/outbound/target-errors.ts
|
|
168
|
+
function missingTargetMessage(provider, hint) {
|
|
169
|
+
return `Delivering to ${provider} requires target${formatTargetHint(hint)}`;
|
|
170
|
+
}
|
|
171
|
+
function missingTargetError(provider, hint) {
|
|
172
|
+
return new Error(missingTargetMessage(provider, hint));
|
|
173
|
+
}
|
|
174
|
+
function ambiguousTargetMessage(provider, raw, hint) {
|
|
175
|
+
return `Ambiguous target "${raw}" for ${provider}. Provide a unique name or an explicit id.${formatTargetHint(hint, true)}`;
|
|
176
|
+
}
|
|
177
|
+
function ambiguousTargetError(provider, raw, hint) {
|
|
178
|
+
return new Error(ambiguousTargetMessage(provider, raw, hint));
|
|
179
|
+
}
|
|
180
|
+
function unknownTargetMessage(provider, raw, hint) {
|
|
181
|
+
return `Unknown target "${raw}" for ${provider}.${formatTargetHint(hint, true)}`;
|
|
182
|
+
}
|
|
183
|
+
function unknownTargetError(provider, raw, hint) {
|
|
184
|
+
return new Error(unknownTargetMessage(provider, raw, hint));
|
|
185
|
+
}
|
|
186
|
+
function formatTargetHint(hint, withLabel = false) {
|
|
187
|
+
if (!hint) return "";
|
|
188
|
+
return withLabel ? ` Hint: ${hint}` : ` ${hint}`;
|
|
189
|
+
}
|
|
190
|
+
//#endregion
|
|
191
|
+
export { ToolInputError as a, imageResultFromFile as c, readNumberParam as d, readReactionParams as f, readStringParam as h, ToolAuthorizationError as i, jsonResult as l, readStringOrNumberParam as m, missingTargetError as n, createActionGate as o, readStringArrayParam as p, unknownTargetError as r, imageResult as s, ambiguousTargetError as t, parseAvailableTags as u };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { v as escapeRegExp } from "./logger-D6zRubj0.js";
|
|
2
|
+
//#region src/auto-reply/tokens.ts
|
|
3
|
+
const HEARTBEAT_TOKEN = "HEARTBEAT_OK";
|
|
4
|
+
const SILENT_REPLY_TOKEN = "NO_REPLY";
|
|
5
|
+
const silentExactRegexByToken = /* @__PURE__ */ new Map();
|
|
6
|
+
const silentTrailingRegexByToken = /* @__PURE__ */ new Map();
|
|
7
|
+
function getSilentExactRegex(token) {
|
|
8
|
+
const cached = silentExactRegexByToken.get(token);
|
|
9
|
+
if (cached) return cached;
|
|
10
|
+
const escaped = escapeRegExp(token);
|
|
11
|
+
const regex = new RegExp(`^\\s*${escaped}\\s*$`);
|
|
12
|
+
silentExactRegexByToken.set(token, regex);
|
|
13
|
+
return regex;
|
|
14
|
+
}
|
|
15
|
+
function getSilentTrailingRegex(token) {
|
|
16
|
+
const cached = silentTrailingRegexByToken.get(token);
|
|
17
|
+
if (cached) return cached;
|
|
18
|
+
const escaped = escapeRegExp(token);
|
|
19
|
+
const regex = new RegExp(`(?:^|\\s+|\\*+)${escaped}\\s*$`);
|
|
20
|
+
silentTrailingRegexByToken.set(token, regex);
|
|
21
|
+
return regex;
|
|
22
|
+
}
|
|
23
|
+
function isSilentReplyText(text, token = SILENT_REPLY_TOKEN) {
|
|
24
|
+
if (!text) return false;
|
|
25
|
+
return getSilentExactRegex(token).test(text);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Strip a trailing silent reply token from mixed-content text.
|
|
29
|
+
* Returns the remaining text with the token removed (trimmed).
|
|
30
|
+
* If the result is empty, the entire message should be treated as silent.
|
|
31
|
+
*/
|
|
32
|
+
function stripSilentToken(text, token = SILENT_REPLY_TOKEN) {
|
|
33
|
+
return text.replace(getSilentTrailingRegex(token), "").trim();
|
|
34
|
+
}
|
|
35
|
+
function isSilentReplyPrefixText(text, token = SILENT_REPLY_TOKEN) {
|
|
36
|
+
if (!text) return false;
|
|
37
|
+
const trimmed = text.trimStart();
|
|
38
|
+
if (!trimmed) return false;
|
|
39
|
+
if (trimmed !== trimmed.toUpperCase()) return false;
|
|
40
|
+
const normalized = trimmed.toUpperCase();
|
|
41
|
+
if (!normalized) return false;
|
|
42
|
+
if (normalized.length < 2) return false;
|
|
43
|
+
if (/[^A-Z_]/.test(normalized)) return false;
|
|
44
|
+
const tokenUpper = token.toUpperCase();
|
|
45
|
+
if (!tokenUpper.startsWith(normalized)) return false;
|
|
46
|
+
if (normalized.includes("_")) return true;
|
|
47
|
+
return tokenUpper === "NO_REPLY" && normalized === "NO";
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { stripSilentToken as a, isSilentReplyText as i, SILENT_REPLY_TOKEN as n, isSilentReplyPrefixText as r, HEARTBEAT_TOKEN as t };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import "./paths-BtVqCdw4.js";
|
|
2
|
+
import { Ka as logWebSelfId, Wa as WA_WEB_AUTH_DIR, Ya as pickWebChannel, to as webAuthExists } from "./config-B9ODwgpz.js";
|
|
3
|
+
import "./dispatch-BqlR4dPx.js";
|
|
4
|
+
import "./paths-eFexkPEh.js";
|
|
5
|
+
import "./github-copilot-token-Cxf8QYZb.js";
|
|
6
|
+
import "./logger-D6zRubj0.js";
|
|
7
|
+
import "./env-b9k1PHMI.js";
|
|
8
|
+
import "./send-DP_c8JfR.js";
|
|
9
|
+
import "./fetch-BSKpf2dM.js";
|
|
10
|
+
import "./channel-activity-DO0FEzyj.js";
|
|
11
|
+
import "./fetch-guard-4UVSZ0uS.js";
|
|
12
|
+
import "./local-roots-adnEg9zb.js";
|
|
13
|
+
import "./ir-CugsqGH8.js";
|
|
14
|
+
import "./render-CKf6NJ1M.js";
|
|
15
|
+
import "./tables-D5VgpTmm.js";
|
|
16
|
+
import "./send-l-77_s1_.js";
|
|
17
|
+
import "./target-errors-C6zZ_OpA.js";
|
|
18
|
+
import "./send-CeHhnld6.js";
|
|
19
|
+
import "./deliver-B1fFpKjV.js";
|
|
20
|
+
import "./diagnostic-CxIvS-C2.js";
|
|
21
|
+
import "./pi-model-discovery-Dh4ziodY.js";
|
|
22
|
+
import "./audio-transcription-runner-CTIHpebA.js";
|
|
23
|
+
import "./image-Ch6M4tnJ.js";
|
|
24
|
+
import "./api-key-rotation-CimGYMBc.js";
|
|
25
|
+
import "./proxy-fetch-CJEmoBxi.js";
|
|
26
|
+
import "./tokens-DUnJnpMS.js";
|
|
27
|
+
import "./commands-registry-6no2NNrY.js";
|
|
28
|
+
import "./skill-commands-BohYCgkq.js";
|
|
29
|
+
import "./send-CScblaI4.js";
|
|
30
|
+
import "./outbound-attachment-khXJwucX.js";
|
|
31
|
+
import "./send-Dc5fI6e8.js";
|
|
32
|
+
import "./sqlite-CJE3X7Mv.js";
|
|
33
|
+
import "./fetch-PoxzAANT.js";
|
|
34
|
+
import "./manager-CHy8IclH.js";
|
|
35
|
+
import { n as monitorWebInbox, t as monitorWebChannel } from "./channel-web-Da-__nUF.js";
|
|
36
|
+
import { t as sendMessageWhatsApp } from "./outbound-Wzs2iN7X.js";
|
|
37
|
+
import { i as waitForWaConnection, t as createWaSocket } from "./session-CkOKZaqa.js";
|
|
38
|
+
import { t as loginWeb } from "./login-CYvkQ0At.js";
|
|
39
|
+
export { WA_WEB_AUTH_DIR, createWaSocket, logWebSelfId, loginWeb, monitorWebChannel, monitorWebInbox, pickWebChannel, sendMessageWhatsApp, waitForWaConnection, webAuthExists };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import "./paths-BtVqCdw4.js";
|
|
2
|
+
import { Va as resolveWhatsAppAccount } from "./config-B9ODwgpz.js";
|
|
3
|
+
import "./paths-eFexkPEh.js";
|
|
4
|
+
import "./github-copilot-token-Cxf8QYZb.js";
|
|
5
|
+
import "./logger-D6zRubj0.js";
|
|
6
|
+
import "./env-b9k1PHMI.js";
|
|
7
|
+
import "./fetch-guard-4UVSZ0uS.js";
|
|
8
|
+
import "./local-roots-adnEg9zb.js";
|
|
9
|
+
import "./ir-CugsqGH8.js";
|
|
10
|
+
import "./render-CKf6NJ1M.js";
|
|
11
|
+
import "./tables-D5VgpTmm.js";
|
|
12
|
+
import { f as readReactionParams, h as readStringParam, i as ToolAuthorizationError, l as jsonResult, o as createActionGate } from "./target-errors-C6zZ_OpA.js";
|
|
13
|
+
import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-BiICvIKs.js";
|
|
14
|
+
import { r as sendReactionWhatsApp } from "./outbound-Wzs2iN7X.js";
|
|
15
|
+
//#region src/agents/tools/whatsapp-target-auth.ts
|
|
16
|
+
function resolveAuthorizedWhatsAppOutboundTarget(params) {
|
|
17
|
+
const account = resolveWhatsAppAccount({
|
|
18
|
+
cfg: params.cfg,
|
|
19
|
+
accountId: params.accountId
|
|
20
|
+
});
|
|
21
|
+
const resolution = resolveWhatsAppOutboundTarget({
|
|
22
|
+
to: params.chatJid,
|
|
23
|
+
allowFrom: account.allowFrom ?? [],
|
|
24
|
+
mode: "implicit"
|
|
25
|
+
});
|
|
26
|
+
if (!resolution.ok) throw new ToolAuthorizationError(`WhatsApp ${params.actionLabel} blocked: chatJid "${params.chatJid}" is not in the configured allowFrom list for account "${account.accountId}".`);
|
|
27
|
+
return {
|
|
28
|
+
to: resolution.to,
|
|
29
|
+
accountId: account.accountId
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/agents/tools/whatsapp-actions.ts
|
|
34
|
+
async function handleWhatsAppAction(params, cfg) {
|
|
35
|
+
const action = readStringParam(params, "action", { required: true });
|
|
36
|
+
const isActionEnabled = createActionGate(cfg.channels?.whatsapp?.actions);
|
|
37
|
+
if (action === "react") {
|
|
38
|
+
if (!isActionEnabled("reactions")) throw new Error("WhatsApp reactions are disabled.");
|
|
39
|
+
const chatJid = readStringParam(params, "chatJid", { required: true });
|
|
40
|
+
const messageId = readStringParam(params, "messageId", { required: true });
|
|
41
|
+
const { emoji, remove, isEmpty } = readReactionParams(params, { removeErrorMessage: "Emoji is required to remove a WhatsApp reaction." });
|
|
42
|
+
const participant = readStringParam(params, "participant");
|
|
43
|
+
const accountId = readStringParam(params, "accountId");
|
|
44
|
+
const fromMeRaw = params.fromMe;
|
|
45
|
+
const fromMe = typeof fromMeRaw === "boolean" ? fromMeRaw : void 0;
|
|
46
|
+
const resolved = resolveAuthorizedWhatsAppOutboundTarget({
|
|
47
|
+
cfg,
|
|
48
|
+
chatJid,
|
|
49
|
+
accountId,
|
|
50
|
+
actionLabel: "reaction"
|
|
51
|
+
});
|
|
52
|
+
const resolvedEmoji = remove ? "" : emoji;
|
|
53
|
+
await sendReactionWhatsApp(resolved.to, messageId, resolvedEmoji, {
|
|
54
|
+
verbose: false,
|
|
55
|
+
fromMe,
|
|
56
|
+
participant: participant ?? void 0,
|
|
57
|
+
accountId: resolved.accountId
|
|
58
|
+
});
|
|
59
|
+
if (!remove && !isEmpty) return jsonResult({
|
|
60
|
+
ok: true,
|
|
61
|
+
added: emoji
|
|
62
|
+
});
|
|
63
|
+
return jsonResult({
|
|
64
|
+
ok: true,
|
|
65
|
+
removed: true
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
throw new Error(`Unsupported WhatsApp action: ${action}`);
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { handleWhatsAppAction };
|
|
@@ -176,16 +176,19 @@ export default function register(api: OpenClawPluginApi) {
|
|
|
176
176
|
const targetSessionKey =
|
|
177
177
|
parsedChannel === "webchat" || parsedChannel === "web" ? userId : sessionKey;
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
try {
|
|
180
|
+
await sendAuthMessage(
|
|
180
181
|
parsedChannel,
|
|
181
182
|
parsedAccountId,
|
|
182
183
|
parsedTo || userId,
|
|
183
184
|
"✅ 二次认证成功,请重新发送之前的命令(或回复'确认')即可执行。",
|
|
184
185
|
userId,
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
targetSessionKey,
|
|
187
|
+
);
|
|
188
|
+
} catch (err) {
|
|
189
|
+
authManager.restoreNotification(userId, notificationInfo);
|
|
190
|
+
api.logger.error(`[mfa-auth] Failed to send success notification: ${err}`);
|
|
191
|
+
}
|
|
189
192
|
}
|
|
190
193
|
|
|
191
194
|
return undefined;
|
|
@@ -353,16 +356,19 @@ export default function register(api: OpenClawPluginApi) {
|
|
|
353
356
|
? "✅ 重新认证成功,请继续对话。"
|
|
354
357
|
: "✅ 首次认证成功,请继续对话。";
|
|
355
358
|
|
|
356
|
-
|
|
359
|
+
try {
|
|
360
|
+
await sendAuthMessage(
|
|
357
361
|
parsedChannel,
|
|
358
362
|
parsedAccountId,
|
|
359
363
|
parsedTo || userId,
|
|
360
364
|
messageText,
|
|
361
365
|
userId,
|
|
362
366
|
sessionKey,
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
367
|
+
);
|
|
368
|
+
} catch (err) {
|
|
369
|
+
authManager.restoreNotification(userId, notificationInfo);
|
|
370
|
+
api.logger.error(`[mfa-auth] Failed to send success notification: ${err}`);
|
|
371
|
+
}
|
|
366
372
|
}
|
|
367
373
|
|
|
368
374
|
return;
|
|
@@ -482,11 +488,21 @@ export default function register(api: OpenClawPluginApi) {
|
|
|
482
488
|
`[mfa-auth] Parsed: channel=${parsedChannel}, accountId=${parsedAccountId}, to=${parsedTo}`,
|
|
483
489
|
);
|
|
484
490
|
|
|
485
|
-
|
|
491
|
+
const ctxAny = ctx as Record<string, unknown>;
|
|
492
|
+
const contextSessionKey =
|
|
493
|
+
typeof ctxAny.sessionKey === "string" && ctxAny.sessionKey.trim().length > 0
|
|
494
|
+
? ctxAny.sessionKey.trim()
|
|
495
|
+
: typeof ctxAny.conversationId === "string" && ctxAny.conversationId.trim().length > 0
|
|
496
|
+
? ctxAny.conversationId.trim()
|
|
497
|
+
: "";
|
|
498
|
+
|
|
499
|
+
// Prefer real runtime session key from context to avoid injecting into
|
|
500
|
+
// synthetic IDs like "gateway-client" that have no transcript file.
|
|
486
501
|
const sessionKey =
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
502
|
+
contextSessionKey ||
|
|
503
|
+
(parsedChannel === "webchat" || parsedChannel === "web"
|
|
504
|
+
? `${parsedChannel}:${parsedAccountId}:${parsedTo || userId}`
|
|
505
|
+
: `${parsedChannel}:${parsedAccountId}:${userId}`);
|
|
490
506
|
|
|
491
507
|
api.logger.info(`[mfa-auth] Using sessionKey for reauth: ${sessionKey}`);
|
|
492
508
|
|
|
@@ -656,16 +672,19 @@ function startPollingForAuth(
|
|
|
656
672
|
? "✅ 首次认证成功,请继续对话。"
|
|
657
673
|
: "✅ 二次认证成功,请重新发送之前的命令(或回复'确认')即可执行。";
|
|
658
674
|
|
|
659
|
-
|
|
675
|
+
try {
|
|
676
|
+
await sendAuthMessage(
|
|
660
677
|
context.channel,
|
|
661
678
|
context.accountId,
|
|
662
679
|
context.to || userId,
|
|
663
680
|
messageText,
|
|
664
681
|
userId,
|
|
665
682
|
context.sessionKey,
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
683
|
+
);
|
|
684
|
+
} catch (err) {
|
|
685
|
+
authManager.restoreNotification(userId, notificationInfo);
|
|
686
|
+
api.logger.error(`[mfa-auth] Failed to send success notification from polling: ${err}`);
|
|
687
|
+
}
|
|
669
688
|
}
|
|
670
689
|
return;
|
|
671
690
|
}
|
|
@@ -252,6 +252,10 @@ export class AuthManager {
|
|
|
252
252
|
return null;
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
+
restoreNotification(userId: string, info: NotificationInfo): void {
|
|
256
|
+
this.pendingNotifications.set(userId, info);
|
|
257
|
+
}
|
|
258
|
+
|
|
255
259
|
isUserVerified(userId: string): boolean {
|
|
256
260
|
return this.isUserVerifiedForSensitiveOps(userId);
|
|
257
261
|
}
|
|
@@ -159,7 +159,11 @@ class NotificationService {
|
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
161
|
const errMsg = String(response?.error?.message ?? "").toLowerCase();
|
|
162
|
-
const shouldTryNext =
|
|
162
|
+
const shouldTryNext =
|
|
163
|
+
errMsg.includes("session not found") ||
|
|
164
|
+
errMsg.includes("transcript file not found") ||
|
|
165
|
+
errMsg.includes("failed to write transcript") ||
|
|
166
|
+
errMsg.includes("unavailable");
|
|
163
167
|
if (shouldTryNext && injectIndex + 1 < candidateSessionKeys.length) {
|
|
164
168
|
injectIndex += 1;
|
|
165
169
|
sendInject(candidateSessionKeys[injectIndex]);
|