mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 20:21:35 +00:00
feat: add Linq channel — real iMessage via API, no Mac required
Adds a complete Linq iMessage channel adapter that replaces the existing iMessage channel's Mac Mini + dedicated Apple ID + SSH wrapper + Full Disk Access setup with a single API key and phone number. Core implementation (src/linq/): - types.ts: Linq webhook event and message types - accounts.ts: Multi-account resolution from config (env/file/inline token) - send.ts: REST outbound via Linq Blue V3 API (messages, typing, reactions) - probe.ts: Health check via GET /v3/phonenumbers - monitor.ts: Webhook HTTP server with HMAC-SHA256 signature verification, replay protection, inbound debouncing, and full dispatch pipeline integration Extension plugin (extensions/linq/): - ChannelPlugin implementation with config, security, setup, outbound, gateway, and status adapters - Supports direct and group chats, reactions, and media Wiring: - Channel registry, dock, config schema, plugin-sdk exports, and plugin runtime all updated to include the new linq channel Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Peter Steinberger
parent
95024d1671
commit
d4a142fd8f
@@ -1010,3 +1010,65 @@ export const MSTeamsConfigSchema = z
|
||||
'channels.msteams.dmPolicy="open" requires channels.msteams.allowFrom to include "*"',
|
||||
});
|
||||
});
|
||||
|
||||
// ── Linq ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
const LinqAllowFromEntry = z.union([z.string(), z.number()]);
|
||||
|
||||
const LinqAccountSchemaBase = z
|
||||
.object({
|
||||
name: z.string().optional(),
|
||||
enabled: z.boolean().optional(),
|
||||
apiToken: z.string().optional().register(sensitive),
|
||||
tokenFile: z.string().optional(),
|
||||
fromPhone: z.string().optional(),
|
||||
dmPolicy: DmPolicySchema.optional(),
|
||||
allowFrom: z.array(LinqAllowFromEntry).optional(),
|
||||
groupPolicy: GroupPolicySchema.optional(),
|
||||
groupAllowFrom: z.array(LinqAllowFromEntry).optional(),
|
||||
mediaMaxMb: z.number().positive().optional(),
|
||||
textChunkLimit: z.number().positive().optional(),
|
||||
webhookUrl: z.string().optional(),
|
||||
webhookSecret: z.string().optional().register(sensitive),
|
||||
webhookPath: z.string().optional(),
|
||||
webhookHost: z.string().optional(),
|
||||
historyLimit: z.number().nonnegative().optional(),
|
||||
blockStreaming: z.boolean().optional(),
|
||||
groups: z
|
||||
.record(
|
||||
z.string(),
|
||||
z
|
||||
.object({
|
||||
requireMention: z.boolean().optional(),
|
||||
tools: ToolPolicySchema,
|
||||
toolsBySender: ToolPolicyBySenderSchema,
|
||||
})
|
||||
.strict()
|
||||
.optional(),
|
||||
)
|
||||
.optional(),
|
||||
responsePrefix: z.string().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const LinqAccountSchema = LinqAccountSchemaBase.superRefine((value, ctx) => {
|
||||
requireOpenAllowFrom({
|
||||
policy: value.dmPolicy,
|
||||
allowFrom: value.allowFrom,
|
||||
ctx,
|
||||
path: ["allowFrom"],
|
||||
message: 'channels.linq.dmPolicy="open" requires channels.linq.allowFrom to include "*"',
|
||||
});
|
||||
});
|
||||
|
||||
export const LinqConfigSchema = LinqAccountSchemaBase.extend({
|
||||
accounts: z.record(z.string(), LinqAccountSchema.optional()).optional(),
|
||||
}).superRefine((value, ctx) => {
|
||||
requireOpenAllowFrom({
|
||||
policy: value.dmPolicy,
|
||||
allowFrom: value.allowFrom,
|
||||
ctx,
|
||||
path: ["allowFrom"],
|
||||
message: 'channels.linq.dmPolicy="open" requires channels.linq.allowFrom to include "*"',
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user