@soimy/dingtalk 3.6.0 → 3.6.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/README.md +4 -1
- package/openclaw.plugin.json +49 -5
- package/package.json +1 -1
- package/src/auth.ts +5 -2
- package/src/card-service.ts +41 -16
- package/src/channel.ts +5 -2
- package/src/config-schema.ts +2 -1
- package/src/config.ts +24 -67
- package/src/gateway/channel-gateway.ts +9 -8
- package/src/inbound-handler.ts +1239 -1061
- package/src/message-context-store.ts +183 -85
- package/src/messaging/channel-actions.ts +2 -1
- package/src/onboarding.ts +15 -6
- package/src/path-utils.ts +49 -0
- package/src/secret-input.ts +216 -0
- package/src/targeting/agent-routing.ts +30 -5
- package/src/types.ts +25 -10
|
@@ -11,8 +11,17 @@ export const DEFAULT_CREATED_AT_MATCH_WINDOW_MS = 2000;
|
|
|
11
11
|
const MAX_RECORDS_PER_SCOPE = 1000;
|
|
12
12
|
|
|
13
13
|
export type MessageContextDirection = "inbound" | "outbound";
|
|
14
|
-
export type MessageAliasKind =
|
|
15
|
-
|
|
14
|
+
export type MessageAliasKind =
|
|
15
|
+
| "inboundMsgId"
|
|
16
|
+
| "messageId"
|
|
17
|
+
| "processQueryKey"
|
|
18
|
+
| "outTrackId"
|
|
19
|
+
| "cardInstanceId";
|
|
20
|
+
export type MessageDeliveryKind =
|
|
21
|
+
| "session"
|
|
22
|
+
| "proactive-text"
|
|
23
|
+
| "proactive-card"
|
|
24
|
+
| "proactive-media";
|
|
16
25
|
export const DEFAULT_OUTBOUND_SENDER = {
|
|
17
26
|
senderId: "bot",
|
|
18
27
|
senderName: "OpenClaw",
|
|
@@ -47,6 +56,7 @@ export interface MessageRecord {
|
|
|
47
56
|
quotedMessageId?: string;
|
|
48
57
|
media?: {
|
|
49
58
|
downloadCode?: string;
|
|
59
|
+
downloadCodes?: string[];
|
|
50
60
|
spaceId?: string;
|
|
51
61
|
fileId?: string;
|
|
52
62
|
};
|
|
@@ -96,6 +106,7 @@ interface BaseUpsertParams {
|
|
|
96
106
|
quotedMessageId?: string;
|
|
97
107
|
media?: {
|
|
98
108
|
downloadCode?: string;
|
|
109
|
+
downloadCodes?: string[];
|
|
99
110
|
spaceId?: string;
|
|
100
111
|
fileId?: string;
|
|
101
112
|
};
|
|
@@ -120,7 +131,11 @@ interface ScopeParams {
|
|
|
120
131
|
const stateCache = new Map<string, MessageContextState>();
|
|
121
132
|
|
|
122
133
|
function getScopeKey(params: ScopeParams): string {
|
|
123
|
-
return JSON.stringify([
|
|
134
|
+
return JSON.stringify([
|
|
135
|
+
params.storePath || "__memory__",
|
|
136
|
+
params.accountId,
|
|
137
|
+
params.conversationId || null,
|
|
138
|
+
]);
|
|
124
139
|
}
|
|
125
140
|
|
|
126
141
|
function fallbackState(): MessageContextState {
|
|
@@ -145,19 +160,26 @@ function normalizeMedia(value: unknown): MessageRecord["media"] | undefined {
|
|
|
145
160
|
if (!candidate) {
|
|
146
161
|
return undefined;
|
|
147
162
|
}
|
|
148
|
-
const downloadCode =
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
163
|
+
const downloadCode =
|
|
164
|
+
typeof candidate.downloadCode === "string" && candidate.downloadCode.trim()
|
|
165
|
+
? candidate.downloadCode.trim()
|
|
166
|
+
: undefined;
|
|
167
|
+
const downloadCodes =
|
|
168
|
+
Array.isArray(candidate.downloadCodes) && candidate.downloadCodes.length > 0
|
|
169
|
+
? candidate.downloadCodes.filter((c: unknown) => typeof c === "string" && c.trim())
|
|
170
|
+
: undefined;
|
|
171
|
+
const spaceId =
|
|
172
|
+
typeof candidate.spaceId === "string" && candidate.spaceId.trim()
|
|
173
|
+
? candidate.spaceId.trim()
|
|
174
|
+
: undefined;
|
|
175
|
+
const fileId =
|
|
176
|
+
typeof candidate.fileId === "string" && candidate.fileId.trim()
|
|
177
|
+
? candidate.fileId.trim()
|
|
178
|
+
: undefined;
|
|
179
|
+
if (!downloadCode && (!downloadCodes || downloadCodes.length === 0) && !spaceId && !fileId) {
|
|
158
180
|
return undefined;
|
|
159
181
|
}
|
|
160
|
-
return { downloadCode, spaceId, fileId };
|
|
182
|
+
return { downloadCode, downloadCodes, spaceId, fileId };
|
|
161
183
|
}
|
|
162
184
|
|
|
163
185
|
function normalizeQuotedRef(value: unknown): QuotedRef | undefined {
|
|
@@ -180,7 +202,9 @@ function normalizeQuotedRef(value: unknown): QuotedRef | undefined {
|
|
|
180
202
|
? candidate.key
|
|
181
203
|
: undefined;
|
|
182
204
|
const valueString =
|
|
183
|
-
typeof candidate.value === "string" && candidate.value.trim()
|
|
205
|
+
typeof candidate.value === "string" && candidate.value.trim()
|
|
206
|
+
? candidate.value.trim()
|
|
207
|
+
: undefined;
|
|
184
208
|
const fallbackCreatedAt =
|
|
185
209
|
typeof candidate.fallbackCreatedAt === "number" && Number.isFinite(candidate.fallbackCreatedAt)
|
|
186
210
|
? candidate.fallbackCreatedAt
|
|
@@ -213,21 +237,26 @@ function normalizeDelivery(value: unknown): MessageRecord["delivery"] | undefine
|
|
|
213
237
|
if (!candidate) {
|
|
214
238
|
return undefined;
|
|
215
239
|
}
|
|
216
|
-
const messageId =
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
240
|
+
const messageId =
|
|
241
|
+
typeof candidate.messageId === "string" && candidate.messageId.trim()
|
|
242
|
+
? candidate.messageId.trim()
|
|
243
|
+
: undefined;
|
|
244
|
+
const processQueryKey =
|
|
245
|
+
typeof candidate.processQueryKey === "string" && candidate.processQueryKey.trim()
|
|
246
|
+
? candidate.processQueryKey.trim()
|
|
247
|
+
: undefined;
|
|
248
|
+
const outTrackId =
|
|
249
|
+
typeof candidate.outTrackId === "string" && candidate.outTrackId.trim()
|
|
250
|
+
? candidate.outTrackId.trim()
|
|
251
|
+
: undefined;
|
|
252
|
+
const cardInstanceId =
|
|
253
|
+
typeof candidate.cardInstanceId === "string" && candidate.cardInstanceId.trim()
|
|
254
|
+
? candidate.cardInstanceId.trim()
|
|
255
|
+
: undefined;
|
|
256
|
+
const kind =
|
|
257
|
+
typeof candidate.kind === "string" && candidate.kind.trim()
|
|
258
|
+
? (candidate.kind.trim() as MessageDeliveryKind)
|
|
259
|
+
: undefined;
|
|
231
260
|
if (!messageId && !processQueryKey && !outTrackId && !cardInstanceId && !kind) {
|
|
232
261
|
return undefined;
|
|
233
262
|
}
|
|
@@ -248,30 +277,46 @@ function normalizeMessageRecord(value: unknown): MessageRecord | null {
|
|
|
248
277
|
if (!candidate) {
|
|
249
278
|
return null;
|
|
250
279
|
}
|
|
251
|
-
const msgId =
|
|
252
|
-
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
280
|
+
const msgId =
|
|
281
|
+
typeof candidate.msgId === "string" && candidate.msgId.trim() ? candidate.msgId.trim() : "";
|
|
282
|
+
const direction =
|
|
283
|
+
candidate.direction === "outbound"
|
|
284
|
+
? "outbound"
|
|
285
|
+
: candidate.direction === "inbound"
|
|
286
|
+
? "inbound"
|
|
287
|
+
: null;
|
|
288
|
+
const accountId =
|
|
289
|
+
typeof candidate.accountId === "string" && candidate.accountId.trim()
|
|
290
|
+
? candidate.accountId.trim()
|
|
291
|
+
: "";
|
|
292
|
+
const conversationId =
|
|
293
|
+
typeof candidate.conversationId === "string" && candidate.conversationId.trim()
|
|
294
|
+
? candidate.conversationId.trim()
|
|
295
|
+
: null;
|
|
296
|
+
const createdAt =
|
|
297
|
+
typeof candidate.createdAt === "number" && Number.isFinite(candidate.createdAt)
|
|
298
|
+
? candidate.createdAt
|
|
299
|
+
: NaN;
|
|
300
|
+
const updatedAt =
|
|
301
|
+
typeof candidate.updatedAt === "number" && Number.isFinite(candidate.updatedAt)
|
|
302
|
+
? candidate.updatedAt
|
|
303
|
+
: Date.now();
|
|
265
304
|
if (!msgId || !direction || !accountId || !Number.isFinite(createdAt)) {
|
|
266
305
|
return null;
|
|
267
306
|
}
|
|
268
|
-
const expiresAt =
|
|
269
|
-
|
|
270
|
-
|
|
307
|
+
const expiresAt =
|
|
308
|
+
typeof candidate.expiresAt === "number" && Number.isFinite(candidate.expiresAt)
|
|
309
|
+
? candidate.expiresAt
|
|
310
|
+
: undefined;
|
|
271
311
|
return {
|
|
272
312
|
msgId,
|
|
273
313
|
direction,
|
|
274
|
-
topic:
|
|
314
|
+
topic:
|
|
315
|
+
candidate.topic === null
|
|
316
|
+
? null
|
|
317
|
+
: typeof candidate.topic === "string"
|
|
318
|
+
? candidate.topic
|
|
319
|
+
: null,
|
|
275
320
|
accountId,
|
|
276
321
|
conversationId,
|
|
277
322
|
createdAt,
|
|
@@ -279,16 +324,26 @@ function normalizeMessageRecord(value: unknown): MessageRecord | null {
|
|
|
279
324
|
expiresAt,
|
|
280
325
|
messageType: typeof candidate.messageType === "string" ? candidate.messageType : undefined,
|
|
281
326
|
text: typeof candidate.text === "string" ? candidate.text : undefined,
|
|
282
|
-
attachmentText:
|
|
327
|
+
attachmentText:
|
|
328
|
+
typeof candidate.attachmentText === "string" ? candidate.attachmentText : undefined,
|
|
283
329
|
attachmentTextSource: normalizeAttachmentTextSource(candidate.attachmentTextSource),
|
|
284
330
|
attachmentTextTruncated: candidate.attachmentTextTruncated === true ? true : undefined,
|
|
285
331
|
attachmentFileName:
|
|
286
332
|
typeof candidate.attachmentFileName === "string" ? candidate.attachmentFileName : undefined,
|
|
287
333
|
quotedRef: normalizeQuotedRef(candidate.quotedRef),
|
|
288
|
-
senderId:
|
|
289
|
-
|
|
334
|
+
senderId:
|
|
335
|
+
typeof candidate.senderId === "string" && candidate.senderId.trim()
|
|
336
|
+
? candidate.senderId.trim()
|
|
337
|
+
: undefined,
|
|
338
|
+
senderName:
|
|
339
|
+
typeof candidate.senderName === "string" && candidate.senderName.trim()
|
|
340
|
+
? candidate.senderName.trim()
|
|
341
|
+
: undefined,
|
|
290
342
|
mentions: normalizeMentions(candidate.mentions),
|
|
291
|
-
chatType:
|
|
343
|
+
chatType:
|
|
344
|
+
candidate.chatType === "direct" || candidate.chatType === "group"
|
|
345
|
+
? candidate.chatType
|
|
346
|
+
: undefined,
|
|
292
347
|
quotedMessageId:
|
|
293
348
|
typeof candidate.quotedMessageId === "string" && candidate.quotedMessageId.trim()
|
|
294
349
|
? candidate.quotedMessageId.trim()
|
|
@@ -327,10 +382,17 @@ function buildAliasEntries(record: MessageRecord): Array<[string, string]> {
|
|
|
327
382
|
}
|
|
328
383
|
|
|
329
384
|
function isRecordExpired(record: MessageRecord, nowMs: number): boolean {
|
|
330
|
-
return
|
|
385
|
+
return (
|
|
386
|
+
typeof record.expiresAt === "number" &&
|
|
387
|
+
Number.isFinite(record.expiresAt) &&
|
|
388
|
+
nowMs >= record.expiresAt
|
|
389
|
+
);
|
|
331
390
|
}
|
|
332
391
|
|
|
333
|
-
function normalizeState(
|
|
392
|
+
function normalizeState(
|
|
393
|
+
state: MessageContextState,
|
|
394
|
+
nowMs: number,
|
|
395
|
+
): { state: MessageContextState; removed: number } {
|
|
334
396
|
const normalizedRecords: Record<string, MessageRecord> = {};
|
|
335
397
|
const sortedRecords = Object.values(state.records)
|
|
336
398
|
.map((record) => normalizeMessageRecord(record))
|
|
@@ -363,12 +425,15 @@ function hydrateState(params: ScopeParams, nowMs: number): MessageContextState {
|
|
|
363
425
|
if (!params.storePath) {
|
|
364
426
|
return fallbackState();
|
|
365
427
|
}
|
|
366
|
-
const persisted = readNamespaceJson<Partial<PersistedMessageContextState>>(
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
428
|
+
const persisted = readNamespaceJson<Partial<PersistedMessageContextState>>(
|
|
429
|
+
MESSAGE_CONTEXT_NAMESPACE,
|
|
430
|
+
{
|
|
431
|
+
storePath: params.storePath,
|
|
432
|
+
scope: { accountId: params.accountId, conversationId: params.conversationId || undefined },
|
|
433
|
+
format: "json",
|
|
434
|
+
fallback: { version: MESSAGE_CONTEXT_VERSION, updatedAt: Date.now(), records: {} },
|
|
435
|
+
},
|
|
436
|
+
);
|
|
372
437
|
const parsedRecords = asRecord(persisted.records) || {};
|
|
373
438
|
const hydrated = fallbackState();
|
|
374
439
|
hydrated.updatedAt = typeof persisted.updatedAt === "number" ? persisted.updatedAt : Date.now();
|
|
@@ -426,14 +491,20 @@ function mergeText(existing: string | undefined, next: string | undefined): stri
|
|
|
426
491
|
return next;
|
|
427
492
|
}
|
|
428
493
|
|
|
429
|
-
function mergeAttachmentText(
|
|
494
|
+
function mergeAttachmentText(
|
|
495
|
+
existing: string | undefined,
|
|
496
|
+
next: string | undefined,
|
|
497
|
+
): string | undefined {
|
|
430
498
|
if (typeof next !== "string") {
|
|
431
499
|
return existing;
|
|
432
500
|
}
|
|
433
501
|
return next;
|
|
434
502
|
}
|
|
435
503
|
|
|
436
|
-
function mergeQuotedRef(
|
|
504
|
+
function mergeQuotedRef(
|
|
505
|
+
existing: QuotedRef | undefined,
|
|
506
|
+
next: QuotedRef | undefined,
|
|
507
|
+
): QuotedRef | undefined {
|
|
437
508
|
if (!existing) {
|
|
438
509
|
return next;
|
|
439
510
|
}
|
|
@@ -448,14 +519,20 @@ function mergeQuotedRef(existing: QuotedRef | undefined, next: QuotedRef | undef
|
|
|
448
519
|
};
|
|
449
520
|
}
|
|
450
521
|
|
|
451
|
-
function mergeStringField(
|
|
522
|
+
function mergeStringField(
|
|
523
|
+
existing: string | undefined,
|
|
524
|
+
next: string | undefined,
|
|
525
|
+
): string | undefined {
|
|
452
526
|
if (typeof next !== "string" || !next.trim()) {
|
|
453
527
|
return existing;
|
|
454
528
|
}
|
|
455
529
|
return next.trim();
|
|
456
530
|
}
|
|
457
531
|
|
|
458
|
-
function mergeMentions(
|
|
532
|
+
function mergeMentions(
|
|
533
|
+
existing: string[] | undefined,
|
|
534
|
+
next: string[] | undefined,
|
|
535
|
+
): string[] | undefined {
|
|
459
536
|
if (!next) {
|
|
460
537
|
return existing;
|
|
461
538
|
}
|
|
@@ -474,6 +551,7 @@ function mergeMedia(
|
|
|
474
551
|
}
|
|
475
552
|
return {
|
|
476
553
|
downloadCode: next.downloadCode || existing.downloadCode,
|
|
554
|
+
downloadCodes: next.downloadCodes || existing.downloadCodes,
|
|
477
555
|
spaceId: next.spaceId || existing.spaceId,
|
|
478
556
|
fileId: next.fileId || existing.fileId,
|
|
479
557
|
};
|
|
@@ -512,7 +590,10 @@ function mergeAttachmentTextTruncated(
|
|
|
512
590
|
return next === undefined ? existing : next;
|
|
513
591
|
}
|
|
514
592
|
|
|
515
|
-
function mergeAttachmentFileName(
|
|
593
|
+
function mergeAttachmentFileName(
|
|
594
|
+
existing: string | undefined,
|
|
595
|
+
next: string | undefined,
|
|
596
|
+
): string | undefined {
|
|
516
597
|
if (typeof next !== "string") {
|
|
517
598
|
return existing;
|
|
518
599
|
}
|
|
@@ -521,7 +602,11 @@ function mergeAttachmentFileName(existing: string | undefined, next: string | un
|
|
|
521
602
|
|
|
522
603
|
function resolveExistingMsgId(
|
|
523
604
|
state: MessageContextState,
|
|
524
|
-
params: {
|
|
605
|
+
params: {
|
|
606
|
+
direction: MessageContextDirection;
|
|
607
|
+
msgId?: string;
|
|
608
|
+
delivery?: MessageRecord["delivery"];
|
|
609
|
+
},
|
|
525
610
|
nowMs: number,
|
|
526
611
|
): string | undefined {
|
|
527
612
|
if (params.direction === "inbound" && params.msgId) {
|
|
@@ -556,11 +641,19 @@ function resolveExistingMsgId(
|
|
|
556
641
|
return undefined;
|
|
557
642
|
}
|
|
558
643
|
|
|
559
|
-
function computeExpiresAt(
|
|
644
|
+
function computeExpiresAt(
|
|
645
|
+
nowMs: number,
|
|
646
|
+
ttlMs?: number,
|
|
647
|
+
ttlReferenceMs?: number,
|
|
648
|
+
): number | undefined {
|
|
560
649
|
if (typeof ttlMs !== "number" || !Number.isFinite(ttlMs) || ttlMs <= 0) {
|
|
561
650
|
return undefined;
|
|
562
651
|
}
|
|
563
|
-
return (
|
|
652
|
+
return (
|
|
653
|
+
(typeof ttlReferenceMs === "number" && Number.isFinite(ttlReferenceMs)
|
|
654
|
+
? ttlReferenceMs
|
|
655
|
+
: nowMs) + ttlMs
|
|
656
|
+
);
|
|
564
657
|
}
|
|
565
658
|
|
|
566
659
|
function pruneStateByCreatedAt(
|
|
@@ -622,11 +715,15 @@ function upsertRecord(
|
|
|
622
715
|
if (params.cleanupCreatedAtTtlDays && params.cleanupCreatedAtTtlDays > 0) {
|
|
623
716
|
state = pruneStateByCreatedAt(state, params.cleanupCreatedAtTtlDays, nowMs).state;
|
|
624
717
|
}
|
|
625
|
-
const existingMsgId = resolveExistingMsgId(
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
718
|
+
const existingMsgId = resolveExistingMsgId(
|
|
719
|
+
state,
|
|
720
|
+
{
|
|
721
|
+
direction: params.direction,
|
|
722
|
+
msgId: params.msgId,
|
|
723
|
+
delivery: params.delivery,
|
|
724
|
+
},
|
|
725
|
+
nowMs,
|
|
726
|
+
);
|
|
630
727
|
const canonicalMsgId =
|
|
631
728
|
existingMsgId ||
|
|
632
729
|
params.msgId ||
|
|
@@ -648,9 +745,7 @@ function upsertRecord(
|
|
|
648
745
|
createdAt: existing?.createdAt ?? params.createdAt,
|
|
649
746
|
updatedAt: nowMs,
|
|
650
747
|
expiresAt:
|
|
651
|
-
expiresAt === undefined
|
|
652
|
-
? existing?.expiresAt
|
|
653
|
-
: Math.max(expiresAt, existing?.expiresAt ?? 0),
|
|
748
|
+
expiresAt === undefined ? existing?.expiresAt : Math.max(expiresAt, existing?.expiresAt ?? 0),
|
|
654
749
|
messageType: params.messageType || existing?.messageType,
|
|
655
750
|
text: mergeText(existing?.text, params.text),
|
|
656
751
|
attachmentText: mergeAttachmentText(existing?.attachmentText, params.attachmentText),
|
|
@@ -692,7 +787,9 @@ export function upsertInboundMessageContext(params: UpsertInboundMessageContextP
|
|
|
692
787
|
);
|
|
693
788
|
}
|
|
694
789
|
|
|
695
|
-
export function upsertOutboundMessageContext(
|
|
790
|
+
export function upsertOutboundMessageContext(
|
|
791
|
+
params: UpsertOutboundMessageContextParams,
|
|
792
|
+
): string | undefined {
|
|
696
793
|
return upsertRecord({
|
|
697
794
|
...params,
|
|
698
795
|
direction: "outbound",
|
|
@@ -780,7 +877,10 @@ export function resolveByQuotedRef(
|
|
|
780
877
|
`[DingTalk][QuotedRef] Resolve outbound by ${quotedRef.key}=${quotedRef.value} hit=no accountId=${params.accountId} conversationId=${params.conversationId || "(none)"}`,
|
|
781
878
|
);
|
|
782
879
|
}
|
|
783
|
-
if (
|
|
880
|
+
if (
|
|
881
|
+
typeof quotedRef.fallbackCreatedAt === "number" &&
|
|
882
|
+
Number.isFinite(quotedRef.fallbackCreatedAt)
|
|
883
|
+
) {
|
|
784
884
|
const record = resolveByCreatedAtWindow({
|
|
785
885
|
...params,
|
|
786
886
|
createdAt: quotedRef.fallbackCreatedAt,
|
|
@@ -828,9 +928,7 @@ export function resolveByCreatedAtWindow(
|
|
|
828
928
|
return bestRecord;
|
|
829
929
|
}
|
|
830
930
|
|
|
831
|
-
export function cleanupExpiredMessageContexts(
|
|
832
|
-
params: ScopeParams & { nowMs?: number },
|
|
833
|
-
): number {
|
|
931
|
+
export function cleanupExpiredMessageContexts(params: ScopeParams & { nowMs?: number }): number {
|
|
834
932
|
const nowMs = params.nowMs ?? Date.now();
|
|
835
933
|
const state = loadState(params, nowMs);
|
|
836
934
|
const beforeCount = Object.keys(state.records).length;
|
|
@@ -850,12 +948,12 @@ export function clearMessageContextCacheForTest(): void {
|
|
|
850
948
|
/**
|
|
851
949
|
* Lists non-expired message-context records for one account/conversation scope in createdAt ascending order.
|
|
852
950
|
*/
|
|
853
|
-
export function listMessageContexts(
|
|
854
|
-
params: ScopeParams & { nowMs?: number },
|
|
855
|
-
): MessageRecord[] {
|
|
951
|
+
export function listMessageContexts(params: ScopeParams & { nowMs?: number }): MessageRecord[] {
|
|
856
952
|
const nowMs = params.nowMs ?? Date.now();
|
|
857
953
|
const state = loadState(params, nowMs);
|
|
858
954
|
return state.recentByCreatedAt
|
|
859
955
|
.map((msgId) => state.records[msgId])
|
|
860
|
-
.filter(
|
|
956
|
+
.filter(
|
|
957
|
+
(record): record is MessageRecord => Boolean(record) && !isRecordExpired(record, nowMs),
|
|
958
|
+
);
|
|
861
959
|
}
|
|
@@ -6,6 +6,7 @@ import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
|
|
|
6
6
|
import { getConfig, stripTargetPrefix } from "../config";
|
|
7
7
|
import { getLogger } from "../logger-context";
|
|
8
8
|
import { resolveOriginalPeerId } from "../peer-id-registry";
|
|
9
|
+
import { hasConfiguredSecretInput } from "../secret-input";
|
|
9
10
|
import { sendMedia, sendMessage } from "../send-service";
|
|
10
11
|
import { parseBooleanLike } from "../utils";
|
|
11
12
|
|
|
@@ -50,7 +51,7 @@ function inferCardOwnerIdFromTarget(target: string): string | undefined {
|
|
|
50
51
|
|
|
51
52
|
function describeDingTalkMessageTool(cfg: OpenClawConfig) {
|
|
52
53
|
const config = getConfig(cfg);
|
|
53
|
-
const configured = Boolean(config.clientId && config.clientSecret);
|
|
54
|
+
const configured = Boolean(config.clientId && hasConfiguredSecretInput(config.clientSecret));
|
|
54
55
|
if (!configured && !(config.accounts && Object.keys(config.accounts).length > 0)) {
|
|
55
56
|
return { actions: [], capabilities: [], schema: null };
|
|
56
57
|
}
|
package/src/onboarding.ts
CHANGED
|
@@ -12,12 +12,17 @@ import {
|
|
|
12
12
|
openUrlInBrowser,
|
|
13
13
|
RegistrationError,
|
|
14
14
|
} from "./device-registration.js";
|
|
15
|
+
import {
|
|
16
|
+
hasConfiguredSecretInput,
|
|
17
|
+
normalizeSecretInputString,
|
|
18
|
+
parseSecretInputString,
|
|
19
|
+
} from "./secret-input.js";
|
|
15
20
|
import type { DingTalkConfig, DingTalkChannelConfig } from "./types.js";
|
|
16
21
|
|
|
17
22
|
const channel = "dingtalk" as const;
|
|
18
23
|
|
|
19
24
|
function isConfigured(account: DingTalkConfig): boolean {
|
|
20
|
-
return Boolean(account.clientId && account.clientSecret);
|
|
25
|
+
return Boolean(account.clientId && hasConfiguredSecretInput(account.clientSecret));
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
function applyAccountNameToChannelSection(params: {
|
|
@@ -354,7 +359,9 @@ function applyGenericSetupInput(params: {
|
|
|
354
359
|
name: params.input.name,
|
|
355
360
|
clientId: typeof params.input.token === "string" ? params.input.token.trim() : undefined,
|
|
356
361
|
clientSecret:
|
|
357
|
-
typeof params.input.password === "string"
|
|
362
|
+
typeof params.input.password === "string"
|
|
363
|
+
? parseSecretInputString(params.input.password)
|
|
364
|
+
: undefined,
|
|
358
365
|
},
|
|
359
366
|
});
|
|
360
367
|
}
|
|
@@ -368,7 +375,9 @@ async function configureDingTalkAccount(params: {
|
|
|
368
375
|
const resolved = resolveDingTalkAccount(cfg, accountId);
|
|
369
376
|
|
|
370
377
|
// ── Credential acquisition: auto-register or manual ────────────────────
|
|
371
|
-
const hasExistingCredentials = Boolean(
|
|
378
|
+
const hasExistingCredentials = Boolean(
|
|
379
|
+
resolved.clientId && hasConfiguredSecretInput(resolved.clientSecret),
|
|
380
|
+
);
|
|
372
381
|
const credentialMethod = await prompter.select({
|
|
373
382
|
message: "How do you want to get DingTalk bot credentials?",
|
|
374
383
|
options: [
|
|
@@ -441,7 +450,7 @@ async function configureDingTalkAccount(params: {
|
|
|
441
450
|
await prompter.text({
|
|
442
451
|
message: "Client Secret (AppSecret)",
|
|
443
452
|
placeholder: "xxx-xxx-xxx-xxx",
|
|
444
|
-
initialValue: resolved.clientSecret
|
|
453
|
+
initialValue: normalizeSecretInputString(resolved.clientSecret),
|
|
445
454
|
validate: (value: string) => (String(value ?? "").trim() ? undefined : "Required"),
|
|
446
455
|
}),
|
|
447
456
|
).trim();
|
|
@@ -461,7 +470,7 @@ async function configureDingTalkAccount(params: {
|
|
|
461
470
|
await prompter.text({
|
|
462
471
|
message: "Client Secret (AppSecret)",
|
|
463
472
|
placeholder: "xxx-xxx-xxx-xxx",
|
|
464
|
-
initialValue: resolved.clientSecret
|
|
473
|
+
initialValue: normalizeSecretInputString(resolved.clientSecret),
|
|
465
474
|
validate: (value: string) => (String(value ?? "").trim() ? undefined : "Required"),
|
|
466
475
|
}),
|
|
467
476
|
).trim();
|
|
@@ -523,7 +532,7 @@ async function configureDingTalkAccount(params: {
|
|
|
523
532
|
accountId,
|
|
524
533
|
input: {
|
|
525
534
|
clientId: String(clientId).trim(),
|
|
526
|
-
clientSecret:
|
|
535
|
+
clientSecret: parseSecretInputString(clientSecret),
|
|
527
536
|
dmPolicy: dmPolicyValue,
|
|
528
537
|
groupPolicy: groupPolicyValue,
|
|
529
538
|
messageType,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as os from "node:os";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
const WINDOWS_ROOT_DIRECTORIES = new Set([
|
|
5
|
+
"Users",
|
|
6
|
+
"Program Files",
|
|
7
|
+
"Program Files (x86)",
|
|
8
|
+
"ProgramData",
|
|
9
|
+
"Windows",
|
|
10
|
+
"Documents and Settings",
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
export function resolveRelativePath(input: string): string {
|
|
14
|
+
const trimmed = input.trim();
|
|
15
|
+
if (!trimmed) {
|
|
16
|
+
return trimmed;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const segments = (value: string): string[] => value.split(/[\\/]+/).filter(Boolean);
|
|
20
|
+
const pathSegments = segments(trimmed);
|
|
21
|
+
const firstSegment = pathSegments[0];
|
|
22
|
+
|
|
23
|
+
if (trimmed === "~") {
|
|
24
|
+
return path.resolve(os.homedir());
|
|
25
|
+
}
|
|
26
|
+
if (trimmed.startsWith("~/") || trimmed.startsWith("~\\")) {
|
|
27
|
+
return path.resolve(os.homedir(), ...segments(trimmed.slice(2)));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (process.platform === "win32") {
|
|
31
|
+
if (/^[a-zA-Z]:[\\/]/.test(trimmed)) {
|
|
32
|
+
return path.win32.normalize(trimmed);
|
|
33
|
+
}
|
|
34
|
+
if (firstSegment && /^[a-zA-Z]:$/.test(firstSegment)) {
|
|
35
|
+
return path.win32.resolve(`${firstSegment}\\`, ...pathSegments.slice(1));
|
|
36
|
+
}
|
|
37
|
+
if (firstSegment && WINDOWS_ROOT_DIRECTORIES.has(firstSegment)) {
|
|
38
|
+
return path.win32.resolve("\\", ...pathSegments);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (/^[\\/]/.test(trimmed)) {
|
|
43
|
+
return path.resolve(path.sep, ...pathSegments);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return path.resolve(process.cwd(), ...pathSegments);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const resolveUserPath = resolveRelativePath;
|