weacpx 0.3.1 → 0.4.0-beta.0

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.
Files changed (67) hide show
  1. package/README.md +109 -26
  2. package/config.example.json +8 -1
  3. package/dist/bridge/bridge-main.js +188 -7
  4. package/dist/channels/channel-scope.d.ts +9 -0
  5. package/dist/channels/cli/provider.d.ts +73 -0
  6. package/dist/channels/cli/registry.d.ts +7 -0
  7. package/dist/channels/cli/weixin-provider.d.ts +2 -0
  8. package/dist/channels/create-channel.d.ts +16 -0
  9. package/dist/channels/media-store.d.ts +29 -0
  10. package/dist/channels/media-types.d.ts +28 -0
  11. package/dist/channels/outbound-media-safety.d.ts +7 -0
  12. package/dist/channels/plugin.d.ts +9 -0
  13. package/dist/channels/types.d.ts +61 -0
  14. package/dist/channels/weixin-channel.d.ts +22 -0
  15. package/dist/cli.js +14701 -8461
  16. package/dist/config/types.d.ts +64 -0
  17. package/dist/logging/app-logger.d.ts +23 -0
  18. package/dist/orchestration/orchestration-types.d.ts +156 -0
  19. package/dist/plugin-api.d.ts +8 -0
  20. package/dist/plugin-api.js +180 -0
  21. package/dist/plugins/compatibility.d.ts +16 -0
  22. package/dist/plugins/known-plugins.d.ts +9 -0
  23. package/dist/plugins/types.d.ts +18 -0
  24. package/dist/version.d.ts +1 -0
  25. package/dist/weixin/agent/interface.d.ts +54 -0
  26. package/dist/weixin/api/api.d.ts +48 -0
  27. package/dist/weixin/api/config-cache.d.ts +18 -0
  28. package/dist/weixin/api/session-guard.d.ts +15 -0
  29. package/dist/weixin/api/types.d.ts +201 -0
  30. package/dist/weixin/auth/accounts.d.ts +63 -0
  31. package/dist/weixin/auth/login-qr.d.ts +31 -0
  32. package/dist/weixin/bot.d.ts +54 -0
  33. package/dist/weixin/cdn/aes-ecb.d.ts +6 -0
  34. package/dist/weixin/cdn/cdn-upload.d.ts +17 -0
  35. package/dist/weixin/cdn/cdn-url.d.ts +11 -0
  36. package/dist/weixin/cdn/pic-decrypt.d.ts +9 -0
  37. package/dist/weixin/cdn/upload.d.ts +42 -0
  38. package/dist/weixin/index.d.ts +6 -0
  39. package/dist/weixin/media/media-download.d.ts +18 -0
  40. package/dist/weixin/media/mime.d.ts +6 -0
  41. package/dist/weixin/media/silk-transcode.d.ts +8 -0
  42. package/dist/weixin/messaging/conversation-executor.d.ts +7 -0
  43. package/dist/weixin/messaging/debug-mode.d.ts +9 -0
  44. package/dist/weixin/messaging/deliver-coordinator-message.d.ts +22 -0
  45. package/dist/weixin/messaging/deliver-orchestration-task-notice.d.ts +18 -0
  46. package/dist/weixin/messaging/deliver-orchestration-task-progress.d.ts +16 -0
  47. package/dist/weixin/messaging/error-notice.d.ts +13 -0
  48. package/dist/weixin/messaging/execute-chat-turn.d.ts +12 -0
  49. package/dist/weixin/messaging/final-heads-up.d.ts +5 -0
  50. package/dist/weixin/messaging/handle-weixin-message-turn.d.ts +30 -0
  51. package/dist/weixin/messaging/inbound.d.ts +63 -0
  52. package/dist/weixin/messaging/orchestration-notice-accounts.d.ts +2 -0
  53. package/dist/weixin/messaging/quota-errors.d.ts +8 -0
  54. package/dist/weixin/messaging/quota-manager.d.ts +44 -0
  55. package/dist/weixin/messaging/send-errors.d.ts +39 -0
  56. package/dist/weixin/messaging/send-media.d.ts +23 -0
  57. package/dist/weixin/messaging/send-orchestration-notice.d.ts +10 -0
  58. package/dist/weixin/messaging/send.d.ts +71 -0
  59. package/dist/weixin/messaging/slash-commands.d.ts +40 -0
  60. package/dist/weixin/monitor/consumer-lock.d.ts +24 -0
  61. package/dist/weixin/monitor/monitor.d.ts +28 -0
  62. package/dist/weixin/storage/state-dir.d.ts +2 -0
  63. package/dist/weixin/storage/sync-buf.d.ts +20 -0
  64. package/dist/weixin/util/logger.d.ts +14 -0
  65. package/dist/weixin/util/random.d.ts +10 -0
  66. package/dist/weixin/util/redact.d.ts +21 -0
  67. package/package.json +41 -17
@@ -0,0 +1,63 @@
1
+ import type { ChannelMediaKind } from "../../channels/media-types.js";
2
+ import type { WeixinMessage, MessageItem } from "../api/types.js";
3
+ /** Store a context token for a given account+user pair. */
4
+ export declare function setContextToken(accountId: string, userId: string, token: string): void;
5
+ /** Retrieve the cached context token for a given account+user pair. */
6
+ export declare function getContextToken(accountId: string, userId: string): string | undefined;
7
+ /** Strip the `weixin:accountId:` prefix from a chat key, returning the bare user id. */
8
+ export declare function normalizeWeixinUserIdFromChatKey(chatKey: string): string;
9
+ /** Inbound context passed to the OpenClaw core pipeline (matches MsgContext shape). */
10
+ export type WeixinMsgContext = {
11
+ Body: string;
12
+ From: string;
13
+ To: string;
14
+ AccountId: string;
15
+ OriginatingChannel: "openclaw-weixin";
16
+ OriginatingTo: string;
17
+ MessageSid: string;
18
+ Timestamp?: number;
19
+ Provider: "openclaw-weixin";
20
+ ChatType: "direct";
21
+ /** Set by monitor after resolveAgentRoute so dispatchReplyFromConfig uses the correct session. */
22
+ SessionKey?: string;
23
+ context_token?: string;
24
+ MediaUrl?: string;
25
+ MediaPath?: string;
26
+ MediaType?: string;
27
+ /** Raw message body for framework command authorization. */
28
+ CommandBody?: string;
29
+ /** Whether the sender is authorized to execute slash commands. */
30
+ CommandAuthorized?: boolean;
31
+ };
32
+ /** Returns true if the message item is a media type (image, video, file, or voice). */
33
+ export declare function isMediaItem(item: MessageItem): boolean;
34
+ export declare function bodyFromItemList(itemList?: MessageItem[]): string;
35
+ export type WeixinInboundMediaOpts = {
36
+ /** Local path to decrypted image file. */
37
+ decryptedPicPath?: string;
38
+ /** Local path to transcoded/raw voice file (.wav or .silk). */
39
+ decryptedVoicePath?: string;
40
+ /** MIME type for the voice file (e.g. "audio/wav" or "audio/silk"). */
41
+ voiceMediaType?: string;
42
+ /** Local path to decrypted file attachment. */
43
+ decryptedFilePath?: string;
44
+ /** MIME type for the file attachment (guessed from file_name). */
45
+ fileMediaType?: string;
46
+ /** Local path to decrypted video file. */
47
+ decryptedVideoPath?: string;
48
+ };
49
+ /**
50
+ * Convert a WeixinMessage from getUpdates to the inbound MsgContext for the core pipeline.
51
+ * Media: only pass MediaPath (local file, after CDN download + decrypt).
52
+ * We never pass MediaUrl — the upstream CDN URL is encrypted/auth-only.
53
+ * Priority when multiple media types present: image > video > file > voice.
54
+ */
55
+ export declare function weixinMessageToMsgContext(msg: WeixinMessage, accountId: string, opts?: WeixinInboundMediaOpts): WeixinMsgContext;
56
+ /** Extract the context_token from an inbound WeixinMsgContext. */
57
+ export declare function getContextTokenFromMsgContext(ctx: WeixinMsgContext): string | undefined;
58
+ export interface WeixinInboundMediaDescriptor {
59
+ item: MessageItem;
60
+ kind: ChannelMediaKind;
61
+ fileName?: string;
62
+ }
63
+ export declare function extractWeixinMediaDescriptors(itemList?: MessageItem[]): WeixinInboundMediaDescriptor[];
@@ -0,0 +1,2 @@
1
+ import type { OrchestrationTaskRecord } from "../../orchestration/orchestration-types";
2
+ export declare function resolveOrchestrationNoticeAccountIds(task: Pick<OrchestrationTaskRecord, "accountId" | "deliveryAccountId">, availableAccountIds: string[]): string[];
@@ -0,0 +1,8 @@
1
+ export declare class QuotaDeferredError extends Error {
2
+ readonly chatKey: string;
3
+ constructor(input: {
4
+ chatKey: string;
5
+ reason: string;
6
+ });
7
+ }
8
+ export declare function isQuotaDeferredError(error: unknown): error is QuotaDeferredError;
@@ -0,0 +1,44 @@
1
+ export declare const MID_BUDGET = 6;
2
+ export declare const FINAL_BUDGET = 4;
3
+ export interface PendingFinalChunk {
4
+ /** Pre-formatted body, already carrying the (k/N) pagination prefix. */
5
+ text: string;
6
+ /** 1-based chunk index. */
7
+ seq: number;
8
+ /** Total chunk count for this final answer. */
9
+ total: number;
10
+ contextToken?: string;
11
+ accountId?: string;
12
+ }
13
+ export interface QuotaSnapshot {
14
+ remaining: number;
15
+ midUsed: number;
16
+ finalUsed: number;
17
+ midRemaining: number;
18
+ finalRemaining: number;
19
+ }
20
+ export interface QuotaObserver {
21
+ onInbound?(chatKey: string): void;
22
+ onMidReserved?(chatKey: string, snapshot: QuotaSnapshot): void;
23
+ onMidRejected?(chatKey: string, snapshot: QuotaSnapshot): void;
24
+ onFinalReserved?(chatKey: string, snapshot: QuotaSnapshot): void;
25
+ onFinalRejected?(chatKey: string, snapshot: QuotaSnapshot): void;
26
+ }
27
+ export declare class QuotaManager {
28
+ private readonly states;
29
+ private readonly observer;
30
+ private readonly normalizeKey;
31
+ constructor(observer?: QuotaObserver, normalizeKey?: (key: string) => string);
32
+ onInbound(chatKey: string): void;
33
+ reserveMidSegment(chatKey: string): boolean;
34
+ reserveFinal(chatKey: string): boolean;
35
+ finalRemaining(chatKey: string): number;
36
+ enqueuePendingFinal(chatKey: string, chunks: PendingFinalChunk[]): void;
37
+ prependPendingFinal(chatKey: string, chunks: PendingFinalChunk[]): void;
38
+ drainPendingFinalUpToBudget(chatKey: string, available: number): PendingFinalChunk[];
39
+ hasPendingFinal(chatKey: string): boolean;
40
+ countPendingFinal(chatKey: string): number;
41
+ clearPendingFinal(chatKey: string): void;
42
+ snapshot(chatKey: string): QuotaSnapshot;
43
+ private getOrCreate;
44
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Structured error type for failed Weixin API calls.
3
+ *
4
+ * Two ways the API signals failure:
5
+ * 1. Non-2xx HTTP status (network / gateway).
6
+ * 2. 2xx HTTP with a JSON body whose `errcode` is non-zero (logical failure,
7
+ * e.g. quota exhausted, invalid context_token, expired session). The
8
+ * original implementation only handled case 1, so logical failures
9
+ * appeared as silent successes — that is why "10 reply quota exhausted"
10
+ * never showed up in the logs.
11
+ */
12
+ export declare class WeixinSendError extends Error {
13
+ readonly endpoint: string;
14
+ readonly httpStatus: number;
15
+ readonly errcode?: number;
16
+ readonly errmsg?: string;
17
+ readonly textPreview: string;
18
+ constructor(input: {
19
+ endpoint: string;
20
+ httpStatus: number;
21
+ errcode?: number;
22
+ errmsg?: string;
23
+ textPreview: string;
24
+ });
25
+ }
26
+ /** Type guard for callers that need to read structured fields. */
27
+ export declare function isWeixinSendError(error: unknown): error is WeixinSendError;
28
+ /**
29
+ * Extract structured fields from any error for logging context.
30
+ * Returns sparse object so spreading into log context only adds what we know.
31
+ */
32
+ export declare function describeWeixinSendError(error: unknown): {
33
+ message: string;
34
+ errcode?: number;
35
+ errmsg?: string;
36
+ httpStatus?: number;
37
+ endpoint?: string;
38
+ textPreview?: string;
39
+ };
@@ -0,0 +1,23 @@
1
+ import type { WeixinApiOptions } from "../api/api.js";
2
+ import type { OutboundChannelMedia } from "../../channels/media-types.js";
3
+ /**
4
+ * Upload a local file and send it as a weixin message, routing by MIME type:
5
+ * video/* → uploadVideoToWeixin + sendVideoMessageWeixin
6
+ * image/* → uploadFileToWeixin + sendImageMessageWeixin
7
+ * else → uploadFileAttachmentToWeixin + sendFileMessageWeixin
8
+ *
9
+ * Used by both the auto-reply deliver path (monitor.ts) and the outbound
10
+ * sendMedia path (channel.ts) so they stay in sync.
11
+ */
12
+ export declare function sendWeixinMediaFile(params: {
13
+ media?: OutboundChannelMedia;
14
+ filePath: string;
15
+ to: string;
16
+ text: string;
17
+ opts: WeixinApiOptions & {
18
+ contextToken?: string;
19
+ };
20
+ cdnBaseUrl: string;
21
+ }): Promise<{
22
+ messageId: string;
23
+ }>;
@@ -0,0 +1,10 @@
1
+ import type { OrchestrationTaskRecord } from "../../orchestration/orchestration-types";
2
+ import { sendMessageWeixin } from "./send.js";
3
+ interface NoticeDeps {
4
+ baseUrl: string;
5
+ token?: string;
6
+ contextToken: string;
7
+ sendMessage?: typeof sendMessageWeixin;
8
+ }
9
+ export declare function sendOrchestrationTaskNotice(task: OrchestrationTaskRecord, deps: NoticeDeps): Promise<void>;
10
+ export {};
@@ -0,0 +1,71 @@
1
+ import type { WeixinApiOptions } from "../api/api.js";
2
+ import type { UploadedFileInfo } from "../cdn/upload.js";
3
+ export declare function generateClientId(): string;
4
+ /**
5
+ * Convert markdown-formatted model reply to plain text for Weixin delivery.
6
+ * Preserves newlines; strips markdown syntax.
7
+ */
8
+ export declare function markdownToPlainText(text: string): string;
9
+ /**
10
+ * Send a plain text message downstream.
11
+ * contextToken is required for all reply sends; missing it breaks conversation association.
12
+ */
13
+ export declare function sendMessageWeixin(params: {
14
+ to: string;
15
+ text: string;
16
+ opts: WeixinApiOptions & {
17
+ contextToken?: string;
18
+ };
19
+ }): Promise<{
20
+ messageId: string;
21
+ }>;
22
+ /**
23
+ * Send an image message downstream using a previously uploaded file.
24
+ * Optionally include a text caption as a separate TEXT item before the image.
25
+ *
26
+ * ImageItem fields:
27
+ * - media.encrypt_query_param: CDN download param
28
+ * - media.aes_key: AES key, base64-encoded
29
+ * - mid_size: original ciphertext file size
30
+ */
31
+ export declare function sendImageMessageWeixin(params: {
32
+ to: string;
33
+ text: string;
34
+ uploaded: UploadedFileInfo;
35
+ opts: WeixinApiOptions & {
36
+ contextToken?: string;
37
+ };
38
+ }): Promise<{
39
+ messageId: string;
40
+ }>;
41
+ /**
42
+ * Send a video message downstream using a previously uploaded file.
43
+ * VideoItem: media (CDN ref), video_size (ciphertext bytes).
44
+ * Includes an optional text caption sent as a separate TEXT item first.
45
+ */
46
+ export declare function sendVideoMessageWeixin(params: {
47
+ to: string;
48
+ text: string;
49
+ uploaded: UploadedFileInfo;
50
+ opts: WeixinApiOptions & {
51
+ contextToken?: string;
52
+ };
53
+ }): Promise<{
54
+ messageId: string;
55
+ }>;
56
+ /**
57
+ * Send a file attachment downstream using a previously uploaded file.
58
+ * FileItem: media (CDN ref), file_name, len (plaintext bytes as string).
59
+ * Includes an optional text caption sent as a separate TEXT item first.
60
+ */
61
+ export declare function sendFileMessageWeixin(params: {
62
+ to: string;
63
+ text: string;
64
+ fileName: string;
65
+ uploaded: UploadedFileInfo;
66
+ opts: WeixinApiOptions & {
67
+ contextToken?: string;
68
+ };
69
+ }): Promise<{
70
+ messageId: string;
71
+ }>;
@@ -0,0 +1,40 @@
1
+ import type { PendingFinalChunk } from "./quota-manager.js";
2
+ export interface SlashCommandResult {
3
+ /** 是否是斜杠指令(true 表示已处理,不需要继续走 AI) */
4
+ handled: boolean;
5
+ }
6
+ export interface SlashCommandContext {
7
+ to: string;
8
+ contextToken?: string;
9
+ baseUrl: string;
10
+ token?: string;
11
+ accountId: string;
12
+ log: (msg: string) => void;
13
+ errLog: (msg: string) => void;
14
+ /** Called when /clear is invoked to reset the agent session. */
15
+ onClear?: () => void | Promise<void>;
16
+ hasPendingFinal?: (chatKey: string) => boolean;
17
+ drainPendingFinal?: (chatKey: string, available: number) => PendingFinalChunk[];
18
+ prependPendingFinal?: (chatKey: string, chunks: PendingFinalChunk[]) => void;
19
+ reserveFinal?: (chatKey: string) => boolean;
20
+ finalRemaining?: (chatKey: string) => number;
21
+ sendText?: (params: {
22
+ to: string;
23
+ text: string;
24
+ contextToken?: string;
25
+ }) => Promise<void>;
26
+ }
27
+ /**
28
+ * v1.4: drain the next wave of pending paginated-final chunks parked by an
29
+ * earlier inbound's overflow. Sends up to `finalRemaining(chatKey)` chunks; if
30
+ * any chunks remain after the wave, appends a heads-up tail to this wave's
31
+ * last chunk so the user knows another `/jx` will pull more. No-op when there
32
+ * is nothing pending or the wiring is incomplete.
33
+ */
34
+ export declare function drainPendingFinalForJx(ctx: SlashCommandContext): Promise<void>;
35
+ /**
36
+ * 尝试处理斜杠指令
37
+ *
38
+ * @returns handled=true 表示该消息已作为指令处理,不需要继续走 AI 管道
39
+ */
40
+ export declare function handleSlashCommand(content: string, ctx: SlashCommandContext, receivedAt: number, eventTimestamp?: number): Promise<SlashCommandResult>;
@@ -0,0 +1,24 @@
1
+ export interface WeixinConsumerLockMetadata {
2
+ pid: number;
3
+ mode: "foreground" | "daemon";
4
+ startedAt: string;
5
+ configPath: string;
6
+ statePath: string;
7
+ hostname?: string;
8
+ }
9
+ export interface WeixinConsumerLock {
10
+ acquire: (meta: WeixinConsumerLockMetadata) => Promise<void>;
11
+ release: () => Promise<void>;
12
+ }
13
+ export declare class ActiveWeixinConsumerLockError extends Error {
14
+ readonly existing: WeixinConsumerLockMetadata;
15
+ readonly lockFilePath: string;
16
+ constructor(lockFilePath: string, existing: WeixinConsumerLockMetadata);
17
+ }
18
+ interface CreateWeixinConsumerLockOptions {
19
+ lockFilePath?: string;
20
+ isProcessRunning?: (pid: number) => boolean;
21
+ onDiagnostic?: (event: "lock_exists" | "lock_invalid_removed" | "lock_stale_removed" | "lock_active_conflict" | "lock_acquired" | "lock_released", context: Record<string, string | number | boolean | undefined>) => void | Promise<void>;
22
+ }
23
+ export declare function createWeixinConsumerLock(options?: CreateWeixinConsumerLockOptions): WeixinConsumerLock;
24
+ export {};
@@ -0,0 +1,28 @@
1
+ import type { Agent } from "../agent/interface.js";
2
+ import type { PendingFinalChunk } from "../messaging/quota-manager.js";
3
+ import type { RuntimeMediaStore } from "../../channels/media-store.js";
4
+ export type MonitorWeixinOpts = {
5
+ baseUrl: string;
6
+ cdnBaseUrl: string;
7
+ token?: string;
8
+ accountId: string;
9
+ agent: Agent;
10
+ abortSignal?: AbortSignal;
11
+ longPollTimeoutMs?: number;
12
+ log?: (msg: string) => void;
13
+ onInbound?: (chatKey: string) => void;
14
+ reserveFinal?: (chatKey: string) => boolean;
15
+ finalRemaining?: (chatKey: string) => number;
16
+ hasPendingFinal?: (chatKey: string) => boolean;
17
+ drainPendingFinal?: (chatKey: string, available: number) => PendingFinalChunk[];
18
+ prependPendingFinal?: (chatKey: string, chunks: PendingFinalChunk[]) => void;
19
+ enqueuePendingFinal?: (chatKey: string, chunks: PendingFinalChunk[]) => void;
20
+ dropPendingFinal?: (chatKey: string) => void;
21
+ mediaStore?: RuntimeMediaStore;
22
+ allowedMediaRoots?: string[];
23
+ };
24
+ /**
25
+ * Long-poll loop: getUpdates → process message → call agent → send reply.
26
+ * Runs until aborted.
27
+ */
28
+ export declare function monitorWeixinProvider(opts: MonitorWeixinOpts): Promise<void>;
@@ -0,0 +1,2 @@
1
+ /** Resolve the OpenClaw state directory (mirrors core logic in src/infra). */
2
+ export declare function resolveStateDir(): string;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Path to the persistent get_updates_buf file for an account.
3
+ * Stored alongside account data: ~/.openclaw/openclaw-weixin/accounts/{accountId}.sync.json
4
+ */
5
+ export declare function getSyncBufFilePath(accountId: string): string;
6
+ export type SyncBufData = {
7
+ get_updates_buf: string;
8
+ };
9
+ /**
10
+ * Load persisted get_updates_buf.
11
+ * Falls back in order:
12
+ * 1. Primary path (normalized accountId, new installs)
13
+ * 2. Compat path (raw accountId derived from pattern, old installs)
14
+ * 3. Legacy single-account path (very old installs without multi-account support)
15
+ */
16
+ export declare function loadGetUpdatesBuf(filePath: string): string | undefined;
17
+ /**
18
+ * Persist get_updates_buf. Creates parent dir if needed.
19
+ */
20
+ export declare function saveGetUpdatesBuf(filePath: string, getUpdatesBuf: string): void;
@@ -0,0 +1,14 @@
1
+ /** Dynamically change the minimum log level at runtime. */
2
+ export declare function setLogLevel(level: string): void;
3
+ export type Logger = {
4
+ info(message: string): void;
5
+ debug(message: string): void;
6
+ warn(message: string): void;
7
+ error(message: string): void;
8
+ /** Returns a child logger whose messages are prefixed with `[accountId]`. */
9
+ withAccount(accountId: string): Logger;
10
+ /** Returns the current main log file path. */
11
+ getLogFilePath(): string;
12
+ close(): void;
13
+ };
14
+ export declare const logger: Logger;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Generate a prefixed unique ID using timestamp + crypto random bytes.
3
+ * Format: `{prefix}:{timestamp}-{8-char hex}`
4
+ */
5
+ export declare function generateId(prefix: string): string;
6
+ /**
7
+ * Generate a temporary file name with random suffix.
8
+ * Format: `{prefix}-{timestamp}-{8-char hex}{ext}`
9
+ */
10
+ export declare function tempFileName(prefix: string, ext: string): string;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Truncate a string, appending a length indicator when trimmed.
3
+ * Returns `""` for empty/undefined input.
4
+ */
5
+ export declare function truncate(s: string | undefined, max: number): string;
6
+ /**
7
+ * Redact a token/secret: show only the first few chars + total length.
8
+ * Returns `"(none)"` when absent.
9
+ */
10
+ export declare function redactToken(token: string | undefined, prefixLen?: number): string;
11
+ /**
12
+ * Redact a JSON body string for safe logging. JSON objects are structurally
13
+ * sanitized so secrets and user-authored message bodies are not written to
14
+ * disk. Non-JSON payloads fall back to length-bounded truncation.
15
+ */
16
+ export declare function redactBody(body: string | undefined, maxLen?: number): string;
17
+ /**
18
+ * Strip query string (which often contains signatures/tokens) from a URL,
19
+ * keeping only origin + pathname.
20
+ */
21
+ export declare function redactUrl(rawUrl: string): string;
package/package.json CHANGED
@@ -1,39 +1,56 @@
1
1
  {
2
2
  "name": "weacpx",
3
+ "version": "0.4.0-beta.0",
3
4
  "description": "使用微信 ClawBot 随时随地通过 `acpx` 控制 Claude Code、Codex 等 Agents。",
4
- "version": "0.3.1",
5
- "main": "index.js",
6
- "directories": {
7
- "doc": "docs",
8
- "test": "tests"
9
- },
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://github.com/gadzan/weacpx.git"
13
- },
14
5
  "keywords": [
15
6
  "acpx",
16
7
  "weixin-agent-sdk",
17
8
  "openclaw",
18
- "weixin"
9
+ "weixin",
10
+ "yuanbao",
11
+ "feishu"
19
12
  ],
20
13
  "author": "gadzan",
21
14
  "license": "MIT",
22
15
  "bugs": {
23
16
  "url": "https://github.com/gadzan/weacpx/issues"
24
17
  },
25
- "homepage": "https://github.com/gadzan/weacpx#readme",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/gadzan/weacpx.git"
21
+ },
26
22
  "type": "module",
27
23
  "bin": {
28
- "weacpx": "dist/cli.js"
24
+ "weacpx": "./dist/cli.js"
25
+ },
26
+ "exports": {
27
+ "./plugin-api": {
28
+ "types": "./dist/plugin-api.d.ts",
29
+ "default": "./dist/plugin-api.js"
30
+ }
29
31
  },
30
32
  "files": [
31
33
  "dist",
32
34
  "README.md",
33
35
  "config.example.json"
34
36
  ],
37
+ "workspaces": [
38
+ "packages/*"
39
+ ],
35
40
  "scripts": {
36
- "build": "bun build ./src/cli.ts ./src/bridge/bridge-main.ts --outdir ./dist --target node --external node-pty",
41
+ "clean:dist": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
42
+ "clean:channel-yuanbao": "node -e \"require('node:fs').rmSync('packages/channel-yuanbao/dist',{recursive:true,force:true})\"",
43
+ "clean:channel-feishu": "node -e \"require('node:fs').rmSync('packages/channel-feishu/dist',{recursive:true,force:true})\"",
44
+ "build": "bun run clean:dist && bun build ./src/cli.ts ./src/bridge/bridge-main.ts ./src/plugin-api.ts --outdir ./dist --target node --external node-pty && bun run build:plugin-api",
45
+ "build:plugin-api": "tsc -p tsconfig.plugin-api.json",
46
+ "build:channel-yuanbao": "bun run build:plugin-api && bun run clean:channel-yuanbao && bun build ./packages/channel-yuanbao/src/index.ts --outdir ./packages/channel-yuanbao/dist --target node --external weacpx && tsc -p packages/channel-yuanbao/tsconfig.json",
47
+ "build:channel-feishu": "bun run build:plugin-api && bun run clean:channel-feishu && bun build ./packages/channel-feishu/src/index.ts --outdir ./packages/channel-feishu/dist --target node --external weacpx && tsc -p packages/channel-feishu/tsconfig.json",
48
+ "build:packages": "bun run build && bun run build:channel-yuanbao && bun run build:channel-feishu",
49
+ "verify:publish": "bun run build:packages && node ./scripts/verify-publish.mjs",
50
+ "publish:weacpx": "bun publish --cwd .",
51
+ "publish:channel-feishu": "bun publish --cwd packages/channel-feishu --access public",
52
+ "publish:channel-yuanbao": "bun publish --cwd packages/channel-yuanbao --access public",
53
+ "publish:plugins": "bun run publish:channel-yuanbao && bun run publish:channel-feishu",
37
54
  "dev": "bun run ./src/cli.ts run",
38
55
  "dry-run": "bun run ./src/dry-run.ts",
39
56
  "login": "bun run ./src/cli.ts login",
@@ -43,13 +60,18 @@
43
60
  "daemon:stop": "bun run ./src/cli.ts stop",
44
61
  "test": "node ./scripts/run-tests.mjs",
45
62
  "test:unit": "node ./scripts/run-tests.mjs tests/unit",
46
- "test:smoke": "node ./scripts/run-tests.mjs tests/smoke"
63
+ "test:smoke": "node ./scripts/run-tests.mjs tests/smoke",
64
+ "smoke:local-install": "node ./scripts/smoke-local-install.mjs"
47
65
  },
48
66
  "dependencies": {
49
67
  "@modelcontextprotocol/sdk": "^1.19.0",
50
- "acpx": "^0.5.3",
68
+ "acpx": "^0.6.1",
51
69
  "node-pty": "^1.1.0",
70
+ "proper-lockfile": "^4.1.2",
71
+ "protobufjs": "^7.5.6",
52
72
  "qrcode-terminal": "^0.12.0",
73
+ "write-file-atomic": "^8.0.0",
74
+ "ws": "^8.20.0",
53
75
  "zod": "^3",
54
76
  "zod-to-json-schema": "^3"
55
77
  },
@@ -60,7 +82,9 @@
60
82
  "node": ">=22"
61
83
  },
62
84
  "devDependencies": {
63
- "@types/bun": "^1.3.11",
85
+ "@types/proper-lockfile": "^4.1.4",
86
+ "@types/write-file-atomic": "^4.0.3",
87
+ "@types/ws": "^8.18.1",
64
88
  "bun-types": "^1.3.11",
65
89
  "typescript": "^6.0.2"
66
90
  }