@openclaw/imessage 2026.10.1-beta.2 → 2026.10.5-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/{accounts-evTpvJMv.mjs → accounts-DacCvDBt.mjs} +23 -45
- package/dist/.setup/{actions-DJqbUmbN.mjs → actions-Hxh12myO.mjs} +54 -101
- package/dist/.setup/{actions.runtime-DL5i-Y4J.mjs → actions.runtime-DOIX6Fkf.mjs} +29 -37
- package/dist/.setup/{api-oq_MryN7.mjs → api-BV8qHfLl.mjs} +7 -7
- package/dist/.setup/{api-SAVMfMoY.mjs → api-DC1yHVGj.mjs} +8 -8
- package/dist/.setup/{approval-handler.runtime-Bj2NGNXF.mjs → approval-handler.runtime-Dc3KzakG.mjs} +38 -66
- package/dist/.setup/{approval-reactions-L9Ul7PAu.mjs → approval-reactions-JvzJCJ4a.mjs} +26 -33
- package/dist/.setup/{channel-CL73qdMG.mjs → channel-9TWBUDkP.mjs} +14 -16
- package/dist/.setup/{channel.runtime-DY7JJ0_9.mjs → channel.runtime-DrLDEY4R.mjs} +198 -362
- package/dist/.setup/{client-12apu4Ip.mjs → client-HixFQQWY.mjs} +34 -38
- package/dist/.setup/{media-contract-DjQGZlfl.mjs → media-contract-BwWs5PM7.mjs} +1 -1
- package/dist/.setup/{message-tool-api-CqfRxLlT.mjs → message-tool-api-B5NfPnFL.mjs} +2 -2
- package/dist/.setup/{question-reactions-DJV-TnA8.mjs → question-reactions-9jrqVZgE.mjs} +20 -25
- package/dist/.setup/{reaction-context-By7kUMBC.mjs → reaction-context-CRXpeYAr.mjs} +1 -1
- package/dist/.setup/{remote-file-BU7pA-Zi.mjs → remote-file-Dq5Asi_F.mjs} +10 -16
- package/dist/.setup/{sanitize-outbound-C0x4BPky.mjs → sanitize-outbound-DpdQERYJ.mjs} +27 -62
- package/dist/.setup/{send-pkYwL6Rt.mjs → send-BZZzMbdi.mjs} +186 -251
- package/dist/.setup/{setup-core-DqOBe-n0.mjs → setup-core-CaRGbZOL.mjs} +15 -46
- package/dist/.setup/{setup-surface-zKhIinwY.mjs → setup-surface-BMWS7VuY.mjs} +2 -2
- package/dist/.setup/{targets-BicBiYsM.mjs → targets-B4oU7n-v.mjs} +47 -69
- package/dist/api.js +7 -7
- package/dist/channel-plugin-api.js +1 -1
- package/dist/contract-api.js +1 -1
- package/dist/doctor-contract-api.js +21 -45
- package/dist/media-contract-api.js +1 -1
- package/dist/message-tool-api.js +1 -1
- package/dist/runtime-api.js +1 -1
- package/dist/setup-entry.js +1 -1
- package/dist/src/chat-db.worker.js +1 -1
- package/package.json +4 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { u as expandIMessageUserPath } from "./accounts-
|
|
2
|
-
import { i as invalidateCachedIMessagePrivateApiStatus } from "./message-tool-api-
|
|
1
|
+
import { u as expandIMessageUserPath } from "./accounts-DacCvDBt.mjs";
|
|
2
|
+
import { i as invalidateCachedIMessagePrivateApiStatus } from "./message-tool-api-B5NfPnFL.mjs";
|
|
3
3
|
import { t as getIMessageRuntime } from "./runtime-Cza4CY5T.mjs";
|
|
4
4
|
import { asNullableRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
5
|
import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
|
|
@@ -10,6 +10,7 @@ import { resolveUserPath } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
|
10
10
|
import { spawn } from "node:child_process";
|
|
11
11
|
import { StringDecoder } from "node:string_decoder";
|
|
12
12
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
13
|
+
import { captureChannelReadAuthority, captureEffectAuthority } from "openclaw/plugin-sdk/fetch-runtime";
|
|
13
14
|
import { raceWithTimeout } from "openclaw/plugin-sdk/time-runtime";
|
|
14
15
|
//#region extensions/imessage/src/chat-context.ts
|
|
15
16
|
const EMAIL_HANDLE_PATTERN = /^[^\s@]+@[^\s@]+$/u;
|
|
@@ -87,7 +88,6 @@ function resolveIMessageChatMatch(cached, current) {
|
|
|
87
88
|
}
|
|
88
89
|
//#endregion
|
|
89
90
|
//#region extensions/imessage/src/constants.ts
|
|
90
|
-
/** Default timeout for iMessage probe/RPC operations (10 seconds). */
|
|
91
91
|
const DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS = 1e4;
|
|
92
92
|
const DEFAULT_IMESSAGE_SEND_TIMEOUT_MS = 18e4;
|
|
93
93
|
//#endregion
|
|
@@ -273,20 +273,16 @@ async function rememberIMessageReplyCache(entry) {
|
|
|
273
273
|
imessageReplyCacheByMessageId.set(messageId, fullEntry);
|
|
274
274
|
const cutoff = Date.now() - IMESSAGE_REPLY_CACHE_TTL_MS;
|
|
275
275
|
const deletedMessageIds = [];
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
imessageReplyCacheByMessageId.delete(oldest);
|
|
287
|
-
deletedMessageIds.push(oldest);
|
|
288
|
-
if (oldEntry?.shortId) imessageShortIdToUuid.delete(oldEntry.shortId);
|
|
289
|
-
}
|
|
276
|
+
const pruneUntil = (retain) => {
|
|
277
|
+
for (const [key, cached] of imessageReplyCacheByMessageId) {
|
|
278
|
+
if (retain(key, cached)) break;
|
|
279
|
+
imessageReplyCacheByMessageId.delete(key);
|
|
280
|
+
deletedMessageIds.push(key);
|
|
281
|
+
if (cached.shortId) imessageShortIdToUuid.delete(cached.shortId);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
pruneUntil((_key, cached) => cached.timestamp >= cutoff);
|
|
285
|
+
pruneUntil((key) => !key || imessageReplyCacheByMessageId.size <= 2e3);
|
|
290
286
|
const counter = imessageShortIdCounter;
|
|
291
287
|
persistence = persistence.then(async () => {
|
|
292
288
|
if (isNewMessage) await persistReplyCacheCounter(counter);
|
|
@@ -532,7 +528,6 @@ var IMessageRpcClient = class {
|
|
|
532
528
|
this.pending = /* @__PURE__ */ new Map();
|
|
533
529
|
this.terminalResolve = null;
|
|
534
530
|
this.reapedResolve = null;
|
|
535
|
-
this.isReaped = false;
|
|
536
531
|
this.child = null;
|
|
537
532
|
this.stopPromise = null;
|
|
538
533
|
this.stdoutFramer = createLfLineFramer((line) => this.handleStdoutLine(line));
|
|
@@ -563,13 +558,8 @@ var IMessageRpcClient = class {
|
|
|
563
558
|
"pipe"
|
|
564
559
|
] });
|
|
565
560
|
this.child = child;
|
|
566
|
-
child.stdout.on("data", (chunk) => {
|
|
567
|
-
if (this.child
|
|
568
|
-
this.stdoutFramer.write(chunk);
|
|
569
|
-
});
|
|
570
|
-
child.stderr?.on("data", (chunk) => {
|
|
571
|
-
if (this.child !== child) return;
|
|
572
|
-
this.stderrFramer.write(chunk);
|
|
561
|
+
for (const [stream, framer] of [[child.stdout, this.stdoutFramer], [child.stderr, this.stderrFramer]]) stream.on("data", (chunk) => {
|
|
562
|
+
if (this.child === child) framer.write(chunk);
|
|
573
563
|
});
|
|
574
564
|
const failFromProcessError = (err) => this.failTransport(err, child);
|
|
575
565
|
child.on("error", failFromProcessError);
|
|
@@ -605,6 +595,17 @@ var IMessageRpcClient = class {
|
|
|
605
595
|
throw await this.terminal;
|
|
606
596
|
}
|
|
607
597
|
async request(method, params, opts) {
|
|
598
|
+
const child = this.child;
|
|
599
|
+
const stdin = child?.stdin;
|
|
600
|
+
const assertReadAuthority = captureChannelReadAuthority();
|
|
601
|
+
return captureEffectAuthority().initiate(() => {
|
|
602
|
+
if (child !== this.child || stdin !== this.child?.stdin) throw new Error("imsg rpc process changed before request initiation");
|
|
603
|
+
assertReadAuthority?.();
|
|
604
|
+
opts?.assertCurrent?.();
|
|
605
|
+
return this.initiateRequest(method, params, opts);
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
async initiateRequest(method, params, opts) {
|
|
608
609
|
if (!this.child || !this.child.stdin) throw new Error("imsg rpc not running");
|
|
609
610
|
const id = this.nextId++;
|
|
610
611
|
const line = `${JSON.stringify({
|
|
@@ -614,18 +615,17 @@ var IMessageRpcClient = class {
|
|
|
614
615
|
params: params ?? {}
|
|
615
616
|
})}\n`;
|
|
616
617
|
const timeoutMs = opts?.timeoutMs ?? 1e4;
|
|
617
|
-
const
|
|
618
|
-
|
|
619
|
-
const timer = timeoutMs > 0 ? setTimeout(() => {
|
|
620
|
-
this.pending.delete(key);
|
|
621
|
-
reject(/* @__PURE__ */ new Error(`imsg rpc timeout (${method})`));
|
|
622
|
-
}, timeoutMs) : void 0;
|
|
618
|
+
const key = String(id);
|
|
619
|
+
const pendingResponse = new Promise((resolve, reject) => {
|
|
623
620
|
this.pending.set(key, {
|
|
624
621
|
resolve: (value) => resolve(value),
|
|
625
|
-
reject
|
|
626
|
-
timer
|
|
622
|
+
reject
|
|
627
623
|
});
|
|
628
624
|
});
|
|
625
|
+
const response = timeoutMs > 0 ? raceWithTimeout(pendingResponse, timeoutMs, () => {
|
|
626
|
+
this.pending.delete(key);
|
|
627
|
+
throw new Error(`imsg rpc timeout (${method})`);
|
|
628
|
+
}) : pendingResponse;
|
|
629
629
|
try {
|
|
630
630
|
this.child.stdin.write(line, (err) => {
|
|
631
631
|
if (err) this.failTransport(err, this.child);
|
|
@@ -661,7 +661,7 @@ var IMessageRpcClient = class {
|
|
|
661
661
|
if (!await this.waitForReap(IMESSAGE_RPC_CLOSE_GRACE_MS)) throw new Error("imsg rpc did not exit after SIGKILL");
|
|
662
662
|
}
|
|
663
663
|
async waitForReap(timeoutMs) {
|
|
664
|
-
if (this.
|
|
664
|
+
if (!this.reapedResolve) return true;
|
|
665
665
|
return await raceWithTimeout(this.reaped.then(() => true), timeoutMs, () => false);
|
|
666
666
|
}
|
|
667
667
|
signalChild(child, signal) {
|
|
@@ -702,7 +702,6 @@ var IMessageRpcClient = class {
|
|
|
702
702
|
const key = String(parsed.id);
|
|
703
703
|
const pending = this.pending.get(key);
|
|
704
704
|
if (!pending) return;
|
|
705
|
-
if (pending.timer) clearTimeout(pending.timer);
|
|
706
705
|
this.pending.delete(key);
|
|
707
706
|
if (parsed.error) {
|
|
708
707
|
const baseMessage = parsed.error.message ?? "imsg rpc error";
|
|
@@ -739,7 +738,6 @@ var IMessageRpcClient = class {
|
|
|
739
738
|
}
|
|
740
739
|
failAll(err) {
|
|
741
740
|
for (const [key, pending] of this.pending.entries()) {
|
|
742
|
-
if (pending.timer) clearTimeout(pending.timer);
|
|
743
741
|
pending.reject(err);
|
|
744
742
|
this.pending.delete(key);
|
|
745
743
|
}
|
|
@@ -753,8 +751,6 @@ var IMessageRpcClient = class {
|
|
|
753
751
|
return true;
|
|
754
752
|
}
|
|
755
753
|
markReaped() {
|
|
756
|
-
if (this.isReaped) return;
|
|
757
|
-
this.isReaped = true;
|
|
758
754
|
const resolve = this.reapedResolve;
|
|
759
755
|
this.reapedResolve = null;
|
|
760
756
|
resolve?.();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as resolveIMessageAccount } from "./accounts-
|
|
1
|
+
import { o as resolveIMessageAccount } from "./accounts-DacCvDBt.mjs";
|
|
2
2
|
import { mergeInboundPathRoots } from "openclaw/plugin-sdk/channel-inbound";
|
|
3
3
|
//#region extensions/imessage/src/media-contract.ts
|
|
4
4
|
const DEFAULT_IMESSAGE_ATTACHMENT_ROOTS = ["/Users/*/Library/Messages/Attachments"];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as inferIMessageTargetChatType } from "./targets-
|
|
2
|
-
import { c as getCachedIMessageRemoteHost, o as resolveIMessageAccount } from "./accounts-
|
|
1
|
+
import { n as inferIMessageTargetChatType } from "./targets-B4oU7n-v.mjs";
|
|
2
|
+
import { c as getCachedIMessageRemoteHost, o as resolveIMessageAccount } from "./accounts-DacCvDBt.mjs";
|
|
3
3
|
import { createActionGate } from "openclaw/plugin-sdk/channel-actions";
|
|
4
4
|
import { Type } from "typebox";
|
|
5
5
|
import { asDateTimestampMs } from "openclaw/plugin-sdk/number-runtime";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-BBjsoOtd.mjs";
|
|
2
|
-
import { i as normalizeIMessageGuid } from "./actions-
|
|
3
|
-
import { t as resolveIMessageReactionContext } from "./reaction-context-
|
|
2
|
+
import { i as normalizeIMessageGuid } from "./actions-Hxh12myO.mjs";
|
|
3
|
+
import { t as resolveIMessageReactionContext } from "./reaction-context-CRXpeYAr.mjs";
|
|
4
4
|
import { createQuestionReactionTargetStore, questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
|
|
5
5
|
//#region extensions/imessage/src/question-reactions.ts
|
|
6
6
|
var question_reactions_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -20,15 +20,19 @@ const questionReactionTargets = createQuestionReactionTargetStore({
|
|
|
20
20
|
registerChannelDelivery: questionGatewayRuntime.registerChannelDelivery,
|
|
21
21
|
resolveReaction: questionGatewayRuntime.resolveReaction
|
|
22
22
|
});
|
|
23
|
-
function
|
|
24
|
-
const reaction = resolveIMessageReactionContext(message, bodyText);
|
|
25
|
-
if (!reaction) return null;
|
|
26
|
-
const guids =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
function resolveQuestionReaction(params) {
|
|
24
|
+
const reaction = resolveIMessageReactionContext(params.message, params.bodyText);
|
|
25
|
+
if (!reaction || reaction.action !== "added") return null;
|
|
26
|
+
const guids = [...new Set((reaction.targetGuids ?? []).map(normalizeIMessageGuid).filter(Boolean))];
|
|
27
|
+
if (guids.length === 0) return null;
|
|
28
|
+
const optionIndex = questionGatewayRuntime.resolveReactionIndex(reaction.emoji);
|
|
29
|
+
return optionIndex === void 0 ? null : {
|
|
30
|
+
optionIndex,
|
|
31
|
+
identities: guids.map((messageGuid) => ({
|
|
32
|
+
accountId: params.accountId,
|
|
33
|
+
messageGuid
|
|
34
|
+
}))
|
|
35
|
+
};
|
|
32
36
|
}
|
|
33
37
|
function registerIMessageQuestionReactionTargetForDeliveredPayload(params) {
|
|
34
38
|
const binding = questionGatewayRuntime.readReactionBinding(params.payload);
|
|
@@ -46,23 +50,14 @@ function registerIMessageQuestionReactionTargetForDeliveredPayload(params) {
|
|
|
46
50
|
return registered;
|
|
47
51
|
}
|
|
48
52
|
function hasIMessageQuestionReactionTarget(params) {
|
|
49
|
-
const reaction =
|
|
50
|
-
|
|
51
|
-
return questionReactionTargets.has(reaction.guids.map((messageGuid) => ({
|
|
52
|
-
accountId: params.accountId,
|
|
53
|
-
messageGuid
|
|
54
|
-
})));
|
|
53
|
+
const reaction = resolveQuestionReaction(params);
|
|
54
|
+
return reaction ? questionReactionTargets.has(reaction.identities) : false;
|
|
55
55
|
}
|
|
56
56
|
async function maybeResolveIMessageQuestionReaction(params) {
|
|
57
|
-
const reaction =
|
|
58
|
-
|
|
59
|
-
if (!reaction || reaction.action === "removed" || optionIndex === void 0) return false;
|
|
57
|
+
const reaction = resolveQuestionReaction(params);
|
|
58
|
+
if (!reaction) return false;
|
|
60
59
|
return await questionReactionTargets.resolve({
|
|
61
|
-
|
|
62
|
-
accountId: params.accountId,
|
|
63
|
-
messageGuid
|
|
64
|
-
})),
|
|
65
|
-
optionIndex,
|
|
60
|
+
...reaction,
|
|
66
61
|
cfg: params.cfg,
|
|
67
62
|
senderId: params.senderId,
|
|
68
63
|
gatewayUrl: params.gatewayUrl,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as resolveLocalIMessageChatDbPath } from "./accounts-
|
|
2
|
-
import { b as chatContextFromIMessageTarget, l as resolveIMessageCachedResourceBinding, u as resolveIMessageMessageId, x as isIMessageEmailChatIdentifier } from "./client-
|
|
1
|
+
import { p as resolveLocalIMessageChatDbPath } from "./accounts-DacCvDBt.mjs";
|
|
2
|
+
import { b as chatContextFromIMessageTarget, l as resolveIMessageCachedResourceBinding, u as resolveIMessageMessageId, x as isIMessageEmailChatIdentifier } from "./client-HixFQQWY.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { normalizeScpRemoteHost } from "openclaw/plugin-sdk/host-runtime";
|
|
5
5
|
import { createActionGate } from "openclaw/plugin-sdk/channel-actions";
|
|
@@ -188,7 +188,6 @@ async function authorizeIMessageResourceReference(params) {
|
|
|
188
188
|
}
|
|
189
189
|
//#endregion
|
|
190
190
|
//#region extensions/imessage/src/remote-file.ts
|
|
191
|
-
const TOKEN_PATTERN = /^[a-f0-9]{32}$/u;
|
|
192
191
|
const SSH_OPTIONS = [
|
|
193
192
|
"-o",
|
|
194
193
|
"BatchMode=yes",
|
|
@@ -205,8 +204,8 @@ const SSH_OPTIONS = [
|
|
|
205
204
|
];
|
|
206
205
|
const CLEANUP_TIMEOUT_MS = 1e4;
|
|
207
206
|
const log = createSubsystemLogger("channels/imessage");
|
|
208
|
-
async function runChecked(
|
|
209
|
-
const result = await
|
|
207
|
+
async function runChecked(label, argv, options) {
|
|
208
|
+
const result = await runCommandWithTimeout(argv, {
|
|
210
209
|
killProcessTree: true,
|
|
211
210
|
maxOutputBytes: {
|
|
212
211
|
stdout: 4096,
|
|
@@ -223,16 +222,10 @@ async function runChecked(run, label, argv, options) {
|
|
|
223
222
|
throw new Error(`${label} failed (${result.termination}${result.code === null ? "" : `, code ${result.code}`})${detail ? `: ${detail}` : ""}`);
|
|
224
223
|
}
|
|
225
224
|
}
|
|
226
|
-
function requireToken(createToken) {
|
|
227
|
-
const token = createToken().replaceAll("-", "").toLowerCase();
|
|
228
|
-
if (!TOKEN_PATTERN.test(token)) throw new Error("iMessage remote staging generated an invalid temporary token");
|
|
229
|
-
return token;
|
|
230
|
-
}
|
|
231
225
|
async function withIMessageRemoteFile(params) {
|
|
232
226
|
const remoteHost = normalizeScpRemoteHost(params.remoteHost);
|
|
233
227
|
if (!remoteHost) throw new Error("invalid iMessage remoteHost for SSH/SCP staging");
|
|
234
|
-
const
|
|
235
|
-
const remoteDir = `/tmp/openclaw-imessage-${requireToken(params.deps?.createToken ?? randomUUID)}`;
|
|
228
|
+
const remoteDir = `/tmp/openclaw-imessage-${randomUUID().replaceAll("-", "")}`;
|
|
236
229
|
const remotePath = `${remoteDir}/${sanitizeTempFileName(path.basename(params.localPath))}`;
|
|
237
230
|
const createScript = `set -eu
|
|
238
231
|
umask 077
|
|
@@ -246,7 +239,7 @@ rm -rf -- ${remoteDir}
|
|
|
246
239
|
`;
|
|
247
240
|
params.assertDirectAdapterHandoff?.();
|
|
248
241
|
try {
|
|
249
|
-
await runChecked(
|
|
242
|
+
await runChecked("iMessage remote temporary directory allocation", [
|
|
250
243
|
"ssh",
|
|
251
244
|
...SSH_OPTIONS,
|
|
252
245
|
"-T",
|
|
@@ -259,7 +252,7 @@ rm -rf -- ${remoteDir}
|
|
|
259
252
|
signal: params.signal
|
|
260
253
|
});
|
|
261
254
|
params.assertDirectAdapterHandoff?.();
|
|
262
|
-
await runChecked(
|
|
255
|
+
await runChecked("iMessage remote file upload", [
|
|
263
256
|
"scp",
|
|
264
257
|
...SSH_OPTIONS,
|
|
265
258
|
"--",
|
|
@@ -273,7 +266,7 @@ rm -rf -- ${remoteDir}
|
|
|
273
266
|
return await params.use(remotePath);
|
|
274
267
|
} finally {
|
|
275
268
|
try {
|
|
276
|
-
await runChecked(
|
|
269
|
+
await runChecked("iMessage remote file cleanup", [
|
|
277
270
|
"ssh",
|
|
278
271
|
...SSH_OPTIONS,
|
|
279
272
|
"-T",
|
|
@@ -285,7 +278,8 @@ rm -rf -- ${remoteDir}
|
|
|
285
278
|
timeoutMs: CLEANUP_TIMEOUT_MS
|
|
286
279
|
});
|
|
287
280
|
} catch (cleanupError) {
|
|
288
|
-
|
|
281
|
+
const detail = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
|
282
|
+
log.warn(`remote attachment cleanup failed: ${detail}`);
|
|
289
283
|
}
|
|
290
284
|
}
|
|
291
285
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FormatCapabilityProfile, findCodeRegions, isInsideCode, markdownToIR, renderMarkdownWithAttributedRanges, sanitizeAssistantVisibleText, stripMarkdown, tokenizeHtmlTags } from "openclaw/plugin-sdk/text-chunking";
|
|
1
|
+
import { FormatCapabilityProfile, applyMarkdownTextEdits, findCodeRegions, isInsideCode, markdownToIR, renderMarkdownWithAttributedRanges, sanitizeAssistantVisibleText, stripMarkdown, tokenizeHtmlTags } from "openclaw/plugin-sdk/text-chunking";
|
|
2
2
|
//#region extensions/imessage/src/markdown-format.ts
|
|
3
3
|
const IMESSAGE_FORMAT_PROFILE = FormatCapabilityProfile.define({
|
|
4
4
|
mechanism: "ranges",
|
|
@@ -44,32 +44,18 @@ function restoreCodeMarkers(text, ranges, codeRanges) {
|
|
|
44
44
|
text,
|
|
45
45
|
ranges
|
|
46
46
|
};
|
|
47
|
-
let rendered = "";
|
|
48
|
-
let cursor = 0;
|
|
49
47
|
const edits = codeRanges.map((range) => {
|
|
50
48
|
const end = range.start + range.length;
|
|
51
49
|
const content = text.slice(range.start, end);
|
|
52
50
|
const marker = codeDelimiter(content);
|
|
53
51
|
const padding = content.startsWith("`") || content.endsWith("`") ? " " : "";
|
|
54
|
-
rendered += text.slice(cursor, range.start) + `${marker}${padding}${content}${padding}${marker}`;
|
|
55
|
-
cursor = end;
|
|
56
52
|
return {
|
|
53
|
+
start: range.start,
|
|
57
54
|
end,
|
|
58
|
-
|
|
55
|
+
text: `${marker}${padding}${content}${padding}${marker}`
|
|
59
56
|
};
|
|
60
57
|
});
|
|
61
|
-
rendered
|
|
62
|
-
const mapOffset = (offset) => {
|
|
63
|
-
let low = 0;
|
|
64
|
-
let high = edits.length;
|
|
65
|
-
while (low < high) {
|
|
66
|
-
const middle = low + Math.floor((high - low) / 2);
|
|
67
|
-
const edit = edits[middle];
|
|
68
|
-
if (edit && edit.end <= offset) low = middle + 1;
|
|
69
|
-
else high = middle;
|
|
70
|
-
}
|
|
71
|
-
return offset + (edits[low - 1]?.shift ?? 0);
|
|
72
|
-
};
|
|
58
|
+
const { text: rendered, mapOffset } = applyMarkdownTextEdits(text, edits);
|
|
73
59
|
return {
|
|
74
60
|
text: rendered,
|
|
75
61
|
ranges: ranges.map((range) => {
|
|
@@ -175,6 +161,23 @@ function assertSafeIMessageOutboundMarkup(text) {
|
|
|
175
161
|
}
|
|
176
162
|
}
|
|
177
163
|
}
|
|
164
|
+
function findIMessageMarkupEnd(text, start, kind, contentOffset = 2) {
|
|
165
|
+
const terminator = kind === "instruction" ? "?>" : ">";
|
|
166
|
+
let quote;
|
|
167
|
+
let bracketDepth = 0;
|
|
168
|
+
for (let index = start + contentOffset; index <= text.length - terminator.length; index += 1) {
|
|
169
|
+
if (kind === "private" && index - start > MAX_PRIVATE_MARKDOWN_UNWRAP_PASSES ** 2) throw new Error("iMessage outbound runtime scaffolding exceeded its limit");
|
|
170
|
+
const character = text[index];
|
|
171
|
+
if (quote) {
|
|
172
|
+
if (character === quote) quote = void 0;
|
|
173
|
+
} else if (character === "'" || character === "\"") quote = character;
|
|
174
|
+
else if (kind === "declaration" && character === "[") bracketDepth += 1;
|
|
175
|
+
else if (kind === "declaration" && character === "]" && bracketDepth > 0) bracketDepth -= 1;
|
|
176
|
+
else if (kind === "private" && character === "<") throw new Error("iMessage outbound runtime scaffolding is malformed");
|
|
177
|
+
else if (bracketDepth === 0 && text.startsWith(terminator, index)) return index + terminator.length;
|
|
178
|
+
}
|
|
179
|
+
return -1;
|
|
180
|
+
}
|
|
178
181
|
function stripIMessageBalancedPrivateRuntimeBlocks(text, verifyProtectedRoles) {
|
|
179
182
|
const openBlocks = [];
|
|
180
183
|
const completedBlocks = [];
|
|
@@ -219,7 +222,7 @@ function stripIMessageBalancedPrivateRuntimeBlocks(text, verifyProtectedRoles) {
|
|
|
219
222
|
cursor = enclosingTag.end;
|
|
220
223
|
continue;
|
|
221
224
|
}
|
|
222
|
-
let end
|
|
225
|
+
let end;
|
|
223
226
|
let delimiterLength = 0;
|
|
224
227
|
if (text.startsWith("<!--", start)) {
|
|
225
228
|
end = text.indexOf("-->", start + 4);
|
|
@@ -227,36 +230,9 @@ function stripIMessageBalancedPrivateRuntimeBlocks(text, verifyProtectedRoles) {
|
|
|
227
230
|
} else if (/^<!\[CDATA\[/i.test(text.slice(start, start + 9))) {
|
|
228
231
|
end = text.indexOf("]]>", start + 9);
|
|
229
232
|
delimiterLength = 3;
|
|
230
|
-
} else if (text.startsWith("<?", start))
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const character = text[index];
|
|
234
|
-
if (quote) {
|
|
235
|
-
if (character === quote) quote = void 0;
|
|
236
|
-
} else if (character === "'" || character === "\"") quote = character;
|
|
237
|
-
else if (character === "?" && text[index + 1] === ">") {
|
|
238
|
-
end = index;
|
|
239
|
-
delimiterLength = 2;
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
} else if (/^<![a-z][a-z0-9_.:-]*\b/i.test(text.slice(start))) {
|
|
244
|
-
let quote;
|
|
245
|
-
let bracketDepth = 0;
|
|
246
|
-
for (let index = start + 2; index < text.length; index += 1) {
|
|
247
|
-
const character = text[index];
|
|
248
|
-
if (quote) {
|
|
249
|
-
if (character === quote) quote = void 0;
|
|
250
|
-
} else if (character === "'" || character === "\"") quote = character;
|
|
251
|
-
else if (character === "[") bracketDepth += 1;
|
|
252
|
-
else if (character === "]" && bracketDepth > 0) bracketDepth -= 1;
|
|
253
|
-
else if (character === ">" && bracketDepth === 0) {
|
|
254
|
-
end = index;
|
|
255
|
-
delimiterLength = 1;
|
|
256
|
-
break;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
} else if (text.startsWith("<!", start) || text.startsWith("</", start) && start + 2 < text.length && !/[A-Za-z>]/.test(text[start + 2] ?? "")) {
|
|
233
|
+
} else if (text.startsWith("<?", start)) end = findIMessageMarkupEnd(text, start, "instruction");
|
|
234
|
+
else if (/^<![a-z][a-z0-9_.:-]*\b/i.test(text.slice(start))) end = findIMessageMarkupEnd(text, start, "declaration");
|
|
235
|
+
else if (text.startsWith("<!", start) || text.startsWith("</", start) && start + 2 < text.length && !/[A-Za-z>]/.test(text[start + 2] ?? "")) {
|
|
260
236
|
end = text.indexOf(">", start + 2);
|
|
261
237
|
delimiterLength = 1;
|
|
262
238
|
} else {
|
|
@@ -299,19 +275,8 @@ function stripIMessageBalancedPrivateRuntimeBlocks(text, verifyProtectedRoles) {
|
|
|
299
275
|
}
|
|
300
276
|
if (enclosingBlock?.codeRegion && enclosingBlock.codeRegion !== codeRegion) throw new Error("iMessage outbound runtime scaffolding is malformed");
|
|
301
277
|
if (++scannedTags > MAX_PRIVATE_MARKDOWN_UNWRAP_PASSES ** 2) throw new Error("iMessage outbound runtime scaffolding exceeded its limit");
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
for (; end < text.length; end += 1) {
|
|
305
|
-
if (end - start > MAX_PRIVATE_MARKDOWN_UNWRAP_PASSES ** 2) throw new Error("iMessage outbound runtime scaffolding exceeded its limit");
|
|
306
|
-
const character = text[end];
|
|
307
|
-
if (quote) {
|
|
308
|
-
if (character === quote) quote = void 0;
|
|
309
|
-
} else if (character === "'" || character === "\"") quote = character;
|
|
310
|
-
else if (character === "<") throw new Error("iMessage outbound runtime scaffolding is malformed");
|
|
311
|
-
else if (character === ">") break;
|
|
312
|
-
}
|
|
313
|
-
if (end >= text.length || quote) throw new Error("iMessage outbound runtime scaffolding is malformed");
|
|
314
|
-
end += 1;
|
|
278
|
+
const end = findIMessageMarkupEnd(text, start, "private", token[0].length);
|
|
279
|
+
if (end < 0) throw new Error("iMessage outbound runtime scaffolding is malformed");
|
|
315
280
|
if (enclosingBlock?.codeRegion && enclosingBlock.codeRegion === codeRegion) {
|
|
316
281
|
if (!enclosingBlock.nestedCodeRegions) {
|
|
317
282
|
if (codeRegion.end - enclosingBlock.end > MAX_PRIVATE_MARKDOWN_UNWRAP_PASSES ** 3) throw new Error("iMessage outbound runtime scaffolding exceeded its limit");
|