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,64 @@
1
+ export type PermissionMode = "approve-all" | "approve-reads" | "deny-all";
2
+ export type NonInteractivePermissions = "deny" | "fail";
3
+ export type ReplyMode = "stream" | "final" | "verbose";
4
+ /** @deprecated Use ReplyMode. */
5
+ export type WechatReplyMode = ReplyMode;
6
+ export interface ChannelConfig {
7
+ type: string;
8
+ replyMode: ReplyMode;
9
+ options?: Record<string, unknown>;
10
+ }
11
+ /** @deprecated Legacy input shape only. Use ChannelConfig. */
12
+ export interface WechatConfig {
13
+ replyMode: ReplyMode;
14
+ }
15
+ export interface TransportConfig {
16
+ type: "acpx-cli" | "acpx-bridge";
17
+ command?: string;
18
+ sessionInitTimeoutMs?: number;
19
+ permissionMode: PermissionMode;
20
+ nonInteractivePermissions: NonInteractivePermissions;
21
+ }
22
+ export type LoggingLevel = "error" | "info" | "debug";
23
+ export interface LoggingConfig {
24
+ level: LoggingLevel;
25
+ maxSizeBytes: number;
26
+ maxFiles: number;
27
+ retentionDays: number;
28
+ }
29
+ export interface AgentConfig {
30
+ driver: string;
31
+ command?: string;
32
+ }
33
+ export interface WorkspaceConfig {
34
+ cwd: string;
35
+ description?: string;
36
+ }
37
+ export interface OrchestrationConfig {
38
+ maxPendingAgentRequestsPerCoordinator: number;
39
+ allowWorkerChainedRequests: boolean;
40
+ allowedAgentRequestTargets: string[];
41
+ allowedAgentRequestRoles: string[];
42
+ progressHeartbeatSeconds: number;
43
+ }
44
+ export interface ChannelRuntimeConfig {
45
+ id: string;
46
+ type: string;
47
+ enabled: boolean;
48
+ options?: Record<string, unknown>;
49
+ }
50
+ export interface PluginConfig {
51
+ name: string;
52
+ version?: string;
53
+ enabled: boolean;
54
+ }
55
+ export interface AppConfig {
56
+ transport: TransportConfig;
57
+ logging: LoggingConfig;
58
+ channel: ChannelConfig;
59
+ channels: ChannelRuntimeConfig[];
60
+ plugins: PluginConfig[];
61
+ agents: Record<string, AgentConfig>;
62
+ workspaces: Record<string, WorkspaceConfig>;
63
+ orchestration: OrchestrationConfig;
64
+ }
@@ -0,0 +1,23 @@
1
+ import type { LoggingLevel } from "../config/types";
2
+ type LogContextValue = string | number | boolean | null | undefined | Record<string, unknown> | unknown[];
3
+ interface LogContext {
4
+ [key: string]: LogContextValue;
5
+ }
6
+ interface CreateAppLoggerOptions {
7
+ filePath: string;
8
+ level: LoggingLevel;
9
+ maxSizeBytes: number;
10
+ maxFiles: number;
11
+ retentionDays: number;
12
+ now?: () => Date;
13
+ }
14
+ export interface AppLogger {
15
+ debug: (event: string, message: string, context?: LogContext) => Promise<void>;
16
+ info: (event: string, message: string, context?: LogContext) => Promise<void>;
17
+ error: (event: string, message: string, context?: LogContext) => Promise<void>;
18
+ cleanup: () => Promise<void>;
19
+ flush: () => Promise<void>;
20
+ }
21
+ export declare function createNoopAppLogger(): AppLogger;
22
+ export declare function createAppLogger(options: CreateAppLoggerOptions): AppLogger;
23
+ export {};
@@ -0,0 +1,156 @@
1
+ export type OrchestrationTaskStatus = "pending" | "needs_confirmation" | "running" | "blocked" | "waiting_for_human" | "completed" | "failed" | "cancelled";
2
+ export type OrchestrationSourceKind = "human" | "coordinator" | "worker";
3
+ export interface OrchestrationOpenQuestionRecord {
4
+ questionId: string;
5
+ question: string;
6
+ whyBlocked: string;
7
+ whatIsNeeded: string;
8
+ askedAt: string;
9
+ status: "open" | "answered" | "superseded";
10
+ answeredAt?: string;
11
+ answerSource?: "coordinator" | "human";
12
+ answerText?: string;
13
+ packageId?: string;
14
+ lastWakeError?: string;
15
+ lastResumeError?: string;
16
+ }
17
+ export interface OrchestrationReviewPendingRecord {
18
+ reviewId: string;
19
+ reason: "misrouted_answer";
20
+ createdAt: string;
21
+ resultId: string;
22
+ resultText: string;
23
+ }
24
+ export interface OrchestrationCorrectionPendingRecord {
25
+ requestedAt: string;
26
+ reason: "misrouted_answer";
27
+ }
28
+ export interface OrchestrationTaskRecord {
29
+ taskId: string;
30
+ sourceHandle: string;
31
+ sourceKind: OrchestrationSourceKind;
32
+ coordinatorSession: string;
33
+ workerSession?: string;
34
+ workspace: string;
35
+ cwd?: string;
36
+ targetAgent: string;
37
+ role?: string;
38
+ task: string;
39
+ status: OrchestrationTaskStatus;
40
+ summary: string;
41
+ resultText: string;
42
+ createdAt: string;
43
+ updatedAt: string;
44
+ chatKey?: string;
45
+ replyContextToken?: string;
46
+ accountId?: string;
47
+ deliveryAccountId?: string;
48
+ coordinatorInjectedAt?: string;
49
+ cancelRequestedAt?: string;
50
+ cancelCompletedAt?: string;
51
+ lastCancelError?: string;
52
+ noticePending?: boolean;
53
+ noticeSentAt?: string;
54
+ lastNoticeError?: string;
55
+ injectionPending?: boolean;
56
+ injectionAppliedAt?: string;
57
+ lastInjectionError?: string;
58
+ lastProgressAt?: string;
59
+ groupId?: string;
60
+ openQuestion?: OrchestrationOpenQuestionRecord;
61
+ reviewPending?: OrchestrationReviewPendingRecord;
62
+ correctionPending?: OrchestrationCorrectionPendingRecord;
63
+ }
64
+ export interface OrchestrationGroupRecord {
65
+ groupId: string;
66
+ coordinatorSession: string;
67
+ title: string;
68
+ createdAt: string;
69
+ updatedAt: string;
70
+ coordinatorInjectedAt?: string;
71
+ injectionPending?: boolean;
72
+ injectionAppliedAt?: string;
73
+ lastInjectionError?: string;
74
+ }
75
+ export interface OrchestrationGroupSummary {
76
+ group: OrchestrationGroupRecord;
77
+ tasks: OrchestrationTaskRecord[];
78
+ totalTasks: number;
79
+ pendingApprovalTasks: number;
80
+ runningTasks: number;
81
+ completedTasks: number;
82
+ failedTasks: number;
83
+ cancelledTasks: number;
84
+ terminal: boolean;
85
+ }
86
+ export interface ExternalCoordinatorRecord {
87
+ coordinatorSession: string;
88
+ workspace?: string;
89
+ createdAt: string;
90
+ updatedAt: string;
91
+ defaultTargetAgent?: string;
92
+ }
93
+ export interface WorkerBindingRecord {
94
+ sourceHandle: string;
95
+ coordinatorSession: string;
96
+ workspace: string;
97
+ cwd?: string;
98
+ targetAgent: string;
99
+ role?: string;
100
+ }
101
+ export interface OrchestrationQueuedQuestionRecord {
102
+ taskId: string;
103
+ questionId: string;
104
+ enqueuedAt: string;
105
+ }
106
+ export interface OrchestrationCoordinatorQuestionStateRecord {
107
+ activePackageId?: string;
108
+ queuedQuestions: OrchestrationQueuedQuestionRecord[];
109
+ }
110
+ export interface OrchestrationCoordinatorRouteContextRecord {
111
+ coordinatorSession: string;
112
+ chatKey: string;
113
+ accountId?: string;
114
+ replyContextToken?: string;
115
+ updatedAt: string;
116
+ }
117
+ export interface OrchestrationHumanQuestionPackageMessageRecord {
118
+ messageId: string;
119
+ kind: "initial" | "follow_up";
120
+ promptText: string;
121
+ createdAt: string;
122
+ taskQuestions?: Array<{
123
+ taskId: string;
124
+ questionId: string;
125
+ }>;
126
+ routeChatKey?: string;
127
+ routeAccountId?: string;
128
+ routeReplyContextToken?: string;
129
+ deliveredAt?: string;
130
+ deliveredChatKey?: string;
131
+ deliveryAccountId?: string;
132
+ lastDeliveryError?: string;
133
+ }
134
+ export interface OrchestrationHumanQuestionPackageRecord {
135
+ packageId: string;
136
+ coordinatorSession: string;
137
+ status: "active" | "closed";
138
+ createdAt: string;
139
+ updatedAt: string;
140
+ closedAt?: string;
141
+ initialTaskIds: string[];
142
+ openTaskIds: string[];
143
+ resolvedTaskIds: string[];
144
+ messages: OrchestrationHumanQuestionPackageMessageRecord[];
145
+ awaitingReplyMessageId?: string;
146
+ }
147
+ export interface OrchestrationState {
148
+ tasks: Record<string, OrchestrationTaskRecord>;
149
+ workerBindings: Record<string, WorkerBindingRecord>;
150
+ groups: Record<string, OrchestrationGroupRecord>;
151
+ humanQuestionPackages: Record<string, OrchestrationHumanQuestionPackageRecord>;
152
+ coordinatorQuestionState: Record<string, OrchestrationCoordinatorQuestionStateRecord>;
153
+ coordinatorRoutes: Record<string, OrchestrationCoordinatorRouteContextRecord>;
154
+ externalCoordinators: Record<string, ExternalCoordinatorRecord>;
155
+ }
156
+ export declare function createEmptyOrchestrationState(): OrchestrationState;
@@ -0,0 +1,8 @@
1
+ export type { ChannelPluginDefinition } from "./channels/plugin.js";
2
+ export type { ChannelFactory, CreateChannelDeps } from "./channels/create-channel.js";
3
+ export type { ChannelStartInput, ConsumerLock, ConsumerLockMetadata, ConsumerLockOptions, CoordinatorMessageInput, MessageChannelRuntime, OrchestrationDeliveryCallbacks, OutboundQuota, } from "./channels/types.js";
4
+ export type { ChannelCliInput, ChannelCliIo, ChannelCliParseResult, ChannelCliProvider, ChannelCliValidationIssue, } from "./channels/cli/provider.js";
5
+ export type { ChannelRuntimeConfig } from "./config/types.js";
6
+ export type { AppLogger } from "./logging/app-logger.js";
7
+ export type { WeacpxPlugin } from "./plugins/types.js";
8
+ export { WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION, } from "./plugins/types.js";
@@ -0,0 +1,180 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
12
+ var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
20
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
21
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
+ for (let key of __getOwnPropNames(mod))
23
+ if (!__hasOwnProp.call(to, key))
24
+ __defProp(to, key, {
25
+ get: __accessProp.bind(mod, key),
26
+ enumerable: true
27
+ });
28
+ if (canCache)
29
+ cache.set(mod, to);
30
+ return to;
31
+ };
32
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
33
+ var __returnValue = (v) => v;
34
+ function __exportSetter(name, newValue) {
35
+ this[name] = __returnValue.bind(null, newValue);
36
+ }
37
+ var __export = (target, all) => {
38
+ for (var name in all)
39
+ __defProp(target, name, {
40
+ get: all[name],
41
+ enumerable: true,
42
+ configurable: true,
43
+ set: __exportSetter.bind(all, name)
44
+ });
45
+ };
46
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
47
+ var __promiseAll = (args) => Promise.all(args);
48
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
49
+
50
+ // src/plugins/compatibility.ts
51
+ function normalizeCoreVersionForCompat(version) {
52
+ const dashIdx = version.indexOf("-");
53
+ const plusIdx = version.indexOf("+");
54
+ const cutPositions = [dashIdx, plusIdx].filter((i) => i >= 0);
55
+ if (cutPositions.length === 0)
56
+ return version;
57
+ return version.slice(0, Math.min(...cutPositions));
58
+ }
59
+ function compareSemver(a, b) {
60
+ const lhs = parseSemverStrict(a);
61
+ const rhs = parseSemverStrict(b);
62
+ for (let i = 0;i < 3; i += 1) {
63
+ if (lhs[i] < rhs[i])
64
+ return -1;
65
+ if (lhs[i] > rhs[i])
66
+ return 1;
67
+ }
68
+ return 0;
69
+ }
70
+ function parseSemverStrict(value) {
71
+ const match = SEMVER_RE.exec(value);
72
+ if (!match)
73
+ throw new Error(`malformed semver: ${value}`);
74
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
75
+ }
76
+ function parseRange(requirement) {
77
+ const trimmed = requirement.trim();
78
+ if (!trimmed)
79
+ throw new Error("empty version requirement");
80
+ if (trimmed.startsWith(">=")) {
81
+ return { kind: "gte", base: parseSemverStrict(trimmed.slice(2).trim()), raw: trimmed };
82
+ }
83
+ if (trimmed.startsWith("^")) {
84
+ return { kind: "caret", base: parseSemverStrict(trimmed.slice(1).trim()), raw: trimmed };
85
+ }
86
+ if (trimmed.startsWith(">") || trimmed.startsWith("<") || trimmed.startsWith("~") || trimmed.includes(" ")) {
87
+ throw new Error(`unsupported version requirement: ${requirement}`);
88
+ }
89
+ return { kind: "exact", base: parseSemverStrict(trimmed), raw: trimmed };
90
+ }
91
+ function isVersionSatisfied(current, requirement) {
92
+ const range = parseRange(requirement);
93
+ const cur = parseSemverStrict(current);
94
+ switch (range.kind) {
95
+ case "exact":
96
+ return cur[0] === range.base[0] && cur[1] === range.base[1] && cur[2] === range.base[2];
97
+ case "gte":
98
+ return cmpTuple(cur, range.base) >= 0;
99
+ case "caret":
100
+ if (cmpTuple(cur, range.base) < 0)
101
+ return false;
102
+ if (range.base[0] !== 0)
103
+ return cur[0] === range.base[0];
104
+ if (range.base[1] !== 0)
105
+ return cur[0] === 0 && cur[1] === range.base[1];
106
+ return cur[0] === 0 && cur[1] === 0 && cur[2] === range.base[2];
107
+ }
108
+ }
109
+ function cmpTuple(a, b) {
110
+ for (let i = 0;i < 3; i += 1) {
111
+ if (a[i] < b[i])
112
+ return -1;
113
+ if (a[i] > b[i])
114
+ return 1;
115
+ }
116
+ return 0;
117
+ }
118
+ function validatePluginCompatibility(metadata, context) {
119
+ const { packageName, currentWeacpxVersion } = context;
120
+ const apiVersion = metadata.apiVersion;
121
+ if (typeof apiVersion !== "number") {
122
+ throw new Error(`插件 ${packageName} 缺少必需字段 apiVersion`);
123
+ }
124
+ if (!WEACPX_PLUGIN_API_SUPPORTED_VERSIONS.includes(apiVersion)) {
125
+ const supported = WEACPX_PLUGIN_API_SUPPORTED_VERSIONS.join(", ");
126
+ throw new Error(`插件 ${packageName} 使用不支持的 apiVersion ${apiVersion}; supported: ${supported}; ` + `请安装与当前 weacpx 兼容的插件版本 (install a compatible plugin)`);
127
+ }
128
+ if (!currentWeacpxVersion || currentWeacpxVersion === "unknown") {
129
+ return;
130
+ }
131
+ const normalizedCurrent = normalizeCoreVersionForCompat(currentWeacpxVersion);
132
+ if (metadata.minWeacpxVersion !== undefined) {
133
+ if (typeof metadata.minWeacpxVersion !== "string") {
134
+ throw new Error(`插件 ${packageName} 元数据非法:minWeacpxVersion 必须是字符串 (invalid plugin metadata)`);
135
+ }
136
+ let satisfied;
137
+ try {
138
+ satisfied = compareSemver(normalizedCurrent, metadata.minWeacpxVersion) >= 0;
139
+ } catch (error) {
140
+ const detail = error instanceof Error ? error.message : String(error);
141
+ throw new Error(`插件 ${packageName} 元数据非法:minWeacpxVersion (${detail}) (invalid plugin metadata)`);
142
+ }
143
+ if (!satisfied) {
144
+ throw new Error(`插件 ${packageName} requires weacpx >=${metadata.minWeacpxVersion}; ` + `current is ${currentWeacpxVersion}; upgrade weacpx`);
145
+ }
146
+ }
147
+ if (metadata.compatibleWeacpxVersions !== undefined) {
148
+ if (typeof metadata.compatibleWeacpxVersions !== "string") {
149
+ throw new Error(`插件 ${packageName} 元数据非法:compatibleWeacpxVersions 必须是字符串 (invalid plugin metadata)`);
150
+ }
151
+ let satisfied;
152
+ try {
153
+ satisfied = isVersionSatisfied(normalizedCurrent, metadata.compatibleWeacpxVersions);
154
+ } catch (error) {
155
+ const detail = error instanceof Error ? error.message : String(error);
156
+ throw new Error(`插件 ${packageName} 元数据非法:compatibleWeacpxVersions (${detail}) (invalid plugin metadata)`);
157
+ }
158
+ if (!satisfied) {
159
+ throw new Error(`插件 ${packageName} requires weacpx ${metadata.compatibleWeacpxVersions}; ` + `current is ${currentWeacpxVersion}; upgrade weacpx`);
160
+ }
161
+ }
162
+ }
163
+ var WEACPX_PLUGIN_API_VERSION = 1, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION = "0.4.0", SEMVER_RE;
164
+ var init_compatibility = __esm(() => {
165
+ WEACPX_PLUGIN_API_SUPPORTED_VERSIONS = [1];
166
+ SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/;
167
+ });
168
+
169
+ // src/plugins/types.ts
170
+ var init_types = __esm(() => {
171
+ init_compatibility();
172
+ });
173
+
174
+ // src/plugin-api.ts
175
+ init_types();
176
+ export {
177
+ WEACPX_PLUGIN_MIN_CORE_VERSION,
178
+ WEACPX_PLUGIN_API_VERSION,
179
+ WEACPX_PLUGIN_API_SUPPORTED_VERSIONS
180
+ };
@@ -0,0 +1,16 @@
1
+ export declare const WEACPX_PLUGIN_API_VERSION: 1;
2
+ export declare const WEACPX_PLUGIN_API_SUPPORTED_VERSIONS: readonly number[];
3
+ export declare const WEACPX_PLUGIN_MIN_CORE_VERSION: "0.4.0";
4
+ export declare function normalizeCoreVersionForCompat(version: string): string;
5
+ export declare function compareSemver(a: string, b: string): -1 | 0 | 1;
6
+ export declare function isVersionSatisfied(current: string, requirement: string): boolean;
7
+ export interface PluginCompatibilityMetadata {
8
+ apiVersion?: unknown;
9
+ minWeacpxVersion?: unknown;
10
+ compatibleWeacpxVersions?: unknown;
11
+ }
12
+ export interface PluginCompatibilityContext {
13
+ packageName: string;
14
+ currentWeacpxVersion: string;
15
+ }
16
+ export declare function validatePluginCompatibility(metadata: PluginCompatibilityMetadata, context: PluginCompatibilityContext): void;
@@ -0,0 +1,9 @@
1
+ export interface KnownPlugin {
2
+ packageName: string;
3
+ channels: string[];
4
+ description: string;
5
+ official: true;
6
+ }
7
+ export declare function listKnownPlugins(): KnownPlugin[];
8
+ export declare function findKnownPluginByChannel(channelType: string): KnownPlugin | null;
9
+ export declare function getMovedChannelInstallHint(channelType: string): string | null;
@@ -0,0 +1,18 @@
1
+ import type { ChannelPluginDefinition } from "../channels/plugin.js";
2
+ import { WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION } from "./compatibility.js";
3
+ export { WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION, };
4
+ export interface WeacpxPlugin {
5
+ apiVersion: 1;
6
+ name?: string;
7
+ /**
8
+ * Minimum weacpx core version required by this plugin (e.g. "0.3.3").
9
+ * First-party plugins must declare this; third-party plugins are encouraged to.
10
+ */
11
+ minWeacpxVersion?: string;
12
+ /**
13
+ * Optional explicit weacpx core compatibility range, e.g. ">=0.3.3" or "^0.3.3".
14
+ * If both `minWeacpxVersion` and `compatibleWeacpxVersions` are set, both must hold.
15
+ */
16
+ compatibleWeacpxVersions?: string;
17
+ channels?: ChannelPluginDefinition[];
18
+ }
@@ -0,0 +1 @@
1
+ export declare function readVersion(moduleUrl?: string): string;
@@ -0,0 +1,54 @@
1
+ import type { ChannelMediaAttachment, OutboundChannelMedia } from "../../channels/media-types.js";
2
+ /**
3
+ * Agent interface — any AI backend that can handle a chat message.
4
+ *
5
+ * Implement this interface to connect WeChat to your own AI service.
6
+ * The WeChat bridge calls `chat()` for each inbound message and sends
7
+ * the returned response back to the user.
8
+ */
9
+ export interface Agent {
10
+ /** Process a single message and return a reply. */
11
+ chat(request: ChatRequest): Promise<ChatResponse>;
12
+ /** Return true when the text begins with a command prefix handled by this agent. */
13
+ isKnownCommand?(text: string): boolean;
14
+ /** Clear/reset the session for a given conversation. */
15
+ clearSession?(conversationId: string): void | Promise<void>;
16
+ }
17
+ export interface ChatRequest {
18
+ /** Inbound Weixin account id that received this message. */
19
+ accountId: string;
20
+ /** Conversation / user identifier. Use this to maintain per-user context. */
21
+ conversationId: string;
22
+ /** Text content of the message. */
23
+ text: string;
24
+ /** Attached media file(s) (image, audio, video, or generic file). */
25
+ media?: ChannelMediaAttachment | ChannelMediaAttachment[];
26
+ /**
27
+ * Optional callback for streaming text out during long-running agent
28
+ * processing. When the channel delivers any non-empty reply segment,
29
+ * callers may treat it as the text output channel for that turn and
30
+ * suppress `ChatResponse.text`.
31
+ */
32
+ reply?: (text: string) => Promise<void>;
33
+ /** Latest inbound Weixin context token for follow-up replies in the same chat. */
34
+ replyContextToken?: string;
35
+ /** Channel-provided facts for command authorization and routing policy. */
36
+ metadata?: ChatRequestMetadata;
37
+ }
38
+ export interface ChatRequestMetadata {
39
+ channel?: string;
40
+ chatType?: "direct" | "group";
41
+ senderId?: string;
42
+ senderName?: string;
43
+ groupId?: string;
44
+ isOwner?: boolean;
45
+ }
46
+ export interface ChatResponse {
47
+ /**
48
+ * Final reply text when no streamed `reply()` output was delivered for
49
+ * the same turn. May contain markdown and will be normalized before send.
50
+ */
51
+ text?: string;
52
+ /** Reply media file(s). */
53
+ media?: OutboundChannelMedia | OutboundChannelMedia[];
54
+ }
@@ -0,0 +1,48 @@
1
+ import type { BaseInfo, GetUploadUrlReq, GetUploadUrlResp, GetUpdatesReq, GetUpdatesResp, SendMessageReq, SendTypingReq, GetConfigResp } from "./types.js";
2
+ export type WeixinApiOptions = {
3
+ baseUrl: string;
4
+ token?: string;
5
+ timeoutMs?: number;
6
+ /** Long-poll timeout for getUpdates (server may hold the request up to this). */
7
+ longPollTimeoutMs?: number;
8
+ };
9
+ /** Build the `base_info` payload included in every API request. */
10
+ export declare function buildBaseInfo(): BaseInfo;
11
+ /**
12
+ * GET fetch wrapper: send a GET request to a Weixin API endpoint with timeout + abort.
13
+ * Query parameters should already be encoded in `endpoint`.
14
+ * Returns the raw response text on success; throws on HTTP error or timeout.
15
+ */
16
+ export declare function apiGetFetch(params: {
17
+ baseUrl: string;
18
+ endpoint: string;
19
+ timeoutMs: number;
20
+ label: string;
21
+ }): Promise<string>;
22
+ /**
23
+ * Long-poll getUpdates. Server should hold the request until new messages or timeout.
24
+ *
25
+ * On client-side timeout (no server response within timeoutMs), returns an empty response
26
+ * with ret=0 so the caller can simply retry. This is normal for long-poll.
27
+ */
28
+ export declare function getUpdates(params: GetUpdatesReq & {
29
+ baseUrl: string;
30
+ token?: string;
31
+ timeoutMs?: number;
32
+ abortSignal?: AbortSignal;
33
+ }): Promise<GetUpdatesResp>;
34
+ /** Get a pre-signed CDN upload URL for a file. */
35
+ export declare function getUploadUrl(params: GetUploadUrlReq & WeixinApiOptions): Promise<GetUploadUrlResp>;
36
+ /** Send a single message downstream. */
37
+ export declare function sendMessage(params: WeixinApiOptions & {
38
+ body: SendMessageReq;
39
+ }): Promise<void>;
40
+ /** Fetch bot config (includes typing_ticket) for a given user. */
41
+ export declare function getConfig(params: WeixinApiOptions & {
42
+ ilinkUserId: string;
43
+ contextToken?: string;
44
+ }): Promise<GetConfigResp>;
45
+ /** Send a typing indicator to a user. */
46
+ export declare function sendTyping(params: WeixinApiOptions & {
47
+ body: SendTypingReq;
48
+ }): Promise<void>;
@@ -0,0 +1,18 @@
1
+ /** Subset of getConfig fields that we actually need; add new fields here as needed. */
2
+ export interface CachedConfig {
3
+ typingTicket: string;
4
+ }
5
+ /**
6
+ * Per-user getConfig cache with periodic random refresh (within 24h) and
7
+ * exponential-backoff retry (up to 1h) on failure.
8
+ */
9
+ export declare class WeixinConfigManager {
10
+ private apiOpts;
11
+ private log;
12
+ private cache;
13
+ constructor(apiOpts: {
14
+ baseUrl: string;
15
+ token?: string;
16
+ }, log: (msg: string) => void);
17
+ getForUser(userId: string, contextToken?: string): Promise<CachedConfig>;
18
+ }
@@ -0,0 +1,15 @@
1
+ /** Error code returned by the server when the bot session has expired. */
2
+ export declare const SESSION_EXPIRED_ERRCODE = -14;
3
+ /** Pause all inbound/outbound API calls for `accountId` for one hour. */
4
+ export declare function pauseSession(accountId: string): void;
5
+ /** Returns `true` when the bot is still within its one-hour cooldown window. */
6
+ export declare function isSessionPaused(accountId: string): boolean;
7
+ /** Milliseconds remaining until the pause expires (0 when not paused). */
8
+ export declare function getRemainingPauseMs(accountId: string): number;
9
+ /** Throw if the session is currently paused. Call before any API request. */
10
+ export declare function assertSessionActive(accountId: string): void;
11
+ /**
12
+ * Reset internal state — only for tests.
13
+ * @internal
14
+ */
15
+ export declare function _resetForTest(): void;