@loggie-ai/openclaw-plugin 0.1.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 (55) hide show
  1. package/README.md +205 -0
  2. package/dist/index.d.ts +8 -0
  3. package/dist/index.js +12 -0
  4. package/dist/setup-entry.d.ts +73 -0
  5. package/dist/setup-entry.js +3 -0
  6. package/dist/src/account.d.ts +70 -0
  7. package/dist/src/account.js +182 -0
  8. package/dist/src/channel.d.ts +72 -0
  9. package/dist/src/channel.js +105 -0
  10. package/dist/src/config-schema.d.ts +98 -0
  11. package/dist/src/config-schema.js +55 -0
  12. package/dist/src/cursor-store.d.ts +86 -0
  13. package/dist/src/cursor-store.js +141 -0
  14. package/dist/src/doctor.d.ts +11 -0
  15. package/dist/src/doctor.js +29 -0
  16. package/dist/src/event-types.d.ts +113 -0
  17. package/dist/src/event-types.js +86 -0
  18. package/dist/src/loggie-client.d.ts +33 -0
  19. package/dist/src/loggie-client.js +74 -0
  20. package/dist/src/monitor/connection.d.ts +30 -0
  21. package/dist/src/monitor/connection.js +289 -0
  22. package/dist/src/monitor/event-handler.d.ts +27 -0
  23. package/dist/src/monitor/event-handler.js +90 -0
  24. package/dist/src/monitor/transcript-dispatch.d.ts +16 -0
  25. package/dist/src/monitor/transcript-dispatch.js +124 -0
  26. package/dist/src/monitor/transcript-format.d.ts +2 -0
  27. package/dist/src/monitor/transcript-format.js +41 -0
  28. package/dist/src/object.d.ts +4 -0
  29. package/dist/src/object.js +12 -0
  30. package/dist/src/routing.d.ts +11 -0
  31. package/dist/src/routing.js +13 -0
  32. package/dist/src/runtime.d.ts +3 -0
  33. package/dist/src/runtime.js +6 -0
  34. package/dist/src/status.d.ts +45 -0
  35. package/dist/src/status.js +45 -0
  36. package/index.ts +13 -0
  37. package/openclaw.plugin.json +71 -0
  38. package/package.json +93 -0
  39. package/plugin-inspector.config.json +15 -0
  40. package/setup-entry.ts +4 -0
  41. package/src/account.ts +265 -0
  42. package/src/channel.ts +148 -0
  43. package/src/config-schema.ts +57 -0
  44. package/src/cursor-store.ts +233 -0
  45. package/src/doctor.ts +39 -0
  46. package/src/event-types.ts +105 -0
  47. package/src/loggie-client.ts +111 -0
  48. package/src/monitor/connection.ts +349 -0
  49. package/src/monitor/event-handler.ts +133 -0
  50. package/src/monitor/transcript-dispatch.ts +145 -0
  51. package/src/monitor/transcript-format.ts +49 -0
  52. package/src/object.ts +15 -0
  53. package/src/routing.ts +27 -0
  54. package/src/runtime.ts +13 -0
  55. package/src/status.ts +72 -0
@@ -0,0 +1,124 @@
1
+ import { fetchLoggieTranscriptDetail } from "../loggie-client.js";
2
+ import { buildLoggieRouteSessionKey, buildLoggieSessionId, meetingConversationId } from "../routing.js";
3
+ import { formatTranscriptReadyPrompt } from "./transcript-format.js";
4
+ export function createOpenClawTranscriptDispatcher(params) {
5
+ const agentRuntime = params.runtime.agent;
6
+ return {
7
+ async dispatchTranscriptReady(event) {
8
+ const routeSessionKey = buildLoggieRouteSessionKey({ account: params.account, event });
9
+ const conversationId = meetingConversationId(event);
10
+ const detail = event.payload.detailPath
11
+ ? await fetchLoggieTranscriptDetail({
12
+ account: params.account,
13
+ detailPath: event.payload.detailPath,
14
+ fetchImpl: params.fetchImpl,
15
+ })
16
+ : undefined;
17
+ const body = formatTranscriptReadyPrompt(event, detail);
18
+ const title = event.payload.title?.trim() || "Loggie meeting";
19
+ const timestamp = Date.parse(event.occurredAt);
20
+ const ctxPayload = await params.channelRuntime.inbound.buildContext({
21
+ channel: "loggie",
22
+ accountId: params.account.accountId,
23
+ provider: "loggie",
24
+ surface: "loggie",
25
+ messageId: event.eventId,
26
+ messageIdFull: `loggie:${event.eventId}`,
27
+ timestamp,
28
+ from: `loggie:${event.workspaceId}:${params.account.agentProfileId}`,
29
+ sender: {
30
+ id: params.account.agentProfileId,
31
+ name: "Loggie",
32
+ displayLabel: "Loggie",
33
+ },
34
+ conversation: {
35
+ kind: "group",
36
+ id: conversationId,
37
+ label: title,
38
+ nativeChannelId: conversationId,
39
+ },
40
+ route: {
41
+ routeSessionKey,
42
+ dispatchSessionKey: routeSessionKey,
43
+ accountId: params.account.accountId,
44
+ agentId: params.account.agentId,
45
+ },
46
+ reply: {
47
+ to: conversationId,
48
+ originatingTo: conversationId,
49
+ nativeChannelId: conversationId,
50
+ },
51
+ message: {
52
+ rawBody: body,
53
+ body,
54
+ bodyForAgent: body,
55
+ commandBody: body,
56
+ inboundEventKind: "user_request",
57
+ sourceModality: "text",
58
+ },
59
+ extra: {
60
+ LoggieEventId: event.eventId,
61
+ LoggieCursor: event.cursor,
62
+ LoggieSequence: event.sequence,
63
+ LoggieMeetingId: event.meetingId,
64
+ LoggieMeetingScheduleId: event.meetingScheduleId,
65
+ LoggieDetailPath: event.payload.detailPath,
66
+ },
67
+ });
68
+ const storePath = params.channelRuntime.session.resolveStorePath(undefined, {
69
+ agentId: params.account.agentId,
70
+ });
71
+ const sessionId = buildLoggieSessionId({ account: params.account, event });
72
+ await params.channelRuntime.inbound.runPreparedReply({
73
+ channel: "loggie",
74
+ accountId: params.account.accountId,
75
+ routeSessionKey,
76
+ storePath,
77
+ ctxPayload,
78
+ recordInboundSession: params.channelRuntime.session.recordInboundSession,
79
+ record: {
80
+ createIfMissing: true,
81
+ updateLastRoute: {
82
+ sessionKey: routeSessionKey,
83
+ channel: "loggie",
84
+ to: conversationId,
85
+ accountId: params.account.accountId,
86
+ },
87
+ },
88
+ runDispatch: async () => {
89
+ const workspaceDir = agentRuntime.resolveAgentWorkspaceDir(params.cfg, params.account.agentId);
90
+ await agentRuntime.ensureAgentWorkspace?.({ dir: workspaceDir });
91
+ return agentRuntime.runEmbeddedAgent({
92
+ sessionId,
93
+ sessionKey: routeSessionKey,
94
+ agentId: params.account.agentId,
95
+ messageChannel: "loggie",
96
+ messageProvider: "loggie",
97
+ chatType: "group",
98
+ agentAccountId: params.account.accountId,
99
+ trigger: "user",
100
+ messageTo: conversationId,
101
+ messageThreadId: conversationId,
102
+ groupId: conversationId,
103
+ groupChannel: title,
104
+ senderId: params.account.agentProfileId,
105
+ senderName: "Loggie",
106
+ currentChannelId: conversationId,
107
+ currentMessageId: event.eventId,
108
+ chatId: conversationId,
109
+ workspaceDir,
110
+ agentDir: agentRuntime.resolveAgentDir(params.cfg, params.account.agentId),
111
+ config: params.cfg,
112
+ prompt: body,
113
+ transcriptPrompt: body,
114
+ currentInboundEventKind: "user_request",
115
+ currentInboundContext: { text: body },
116
+ timeoutMs: agentRuntime.resolveAgentTimeoutMs({ cfg: params.cfg }),
117
+ runId: `loggie-${event.eventId}`,
118
+ abortSignal: params.abortSignal,
119
+ });
120
+ },
121
+ });
122
+ },
123
+ };
124
+ }
@@ -0,0 +1,2 @@
1
+ import type { LoggieTranscriptReadyEvent } from "../event-types.js";
2
+ export declare function formatTranscriptReadyPrompt(event: LoggieTranscriptReadyEvent, detail?: unknown): string;
@@ -0,0 +1,41 @@
1
+ const MAX_DETAIL_CHARS = 60_000;
2
+ export function formatTranscriptReadyPrompt(event, detail) {
3
+ const title = event.payload.title?.trim() || "Untitled meeting";
4
+ const meetingDate = event.payload.meetingDate ?? event.occurredAt;
5
+ const lines = [
6
+ `Loggie meeting transcript ready: ${title}`,
7
+ `Meeting ID: ${event.meetingScheduleId ?? event.meetingId}`,
8
+ `Workspace ID: ${event.workspaceId}`,
9
+ `Occurred At: ${event.occurredAt}`,
10
+ `Meeting Date: ${meetingDate}`,
11
+ ];
12
+ if (event.payload.source) {
13
+ lines.push(`Source: ${event.payload.source}`);
14
+ }
15
+ if (event.payload.externalId) {
16
+ lines.push(`External Transcript ID: ${event.payload.externalId}`);
17
+ }
18
+ if (event.payload.detailPath) {
19
+ lines.push(`Transcript Detail Path: ${event.payload.detailPath}`);
20
+ }
21
+ const formattedDetail = formatTranscriptDetail(detail);
22
+ if (formattedDetail) {
23
+ lines.push("", "Transcript Detail:", formattedDetail);
24
+ }
25
+ return lines.join("\n");
26
+ }
27
+ function formatTranscriptDetail(detail) {
28
+ if (detail === undefined || detail === null) {
29
+ return undefined;
30
+ }
31
+ const text = typeof detail === "string"
32
+ ? detail
33
+ : JSON.stringify(detail, null, 2);
34
+ const trimmed = text.trim();
35
+ if (!trimmed) {
36
+ return undefined;
37
+ }
38
+ return trimmed.length > MAX_DETAIL_CHARS
39
+ ? `${trimmed.slice(0, MAX_DETAIL_CHARS)}\n[truncated]`
40
+ : trimmed;
41
+ }
@@ -0,0 +1,4 @@
1
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
2
+ export declare function readString(value: unknown): string | undefined;
3
+ export declare function readBoolean(value: unknown, fallback: boolean): boolean;
4
+ export declare function readInteger(value: unknown, fallback: number): number;
@@ -0,0 +1,12 @@
1
+ export function isRecord(value) {
2
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3
+ }
4
+ export function readString(value) {
5
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
6
+ }
7
+ export function readBoolean(value, fallback) {
8
+ return typeof value === "boolean" ? value : fallback;
9
+ }
10
+ export function readInteger(value, fallback) {
11
+ return Number.isInteger(value) ? value : fallback;
12
+ }
@@ -0,0 +1,11 @@
1
+ import type { ResolvedLoggieAccount } from "./account.js";
2
+ import type { LoggieEventEnvelope } from "./event-types.js";
3
+ export declare function meetingConversationId(event: LoggieEventEnvelope): string;
4
+ export declare function buildLoggieRouteSessionKey(params: {
5
+ account: Pick<ResolvedLoggieAccount, "accountId" | "agentId">;
6
+ event: LoggieEventEnvelope;
7
+ }): string;
8
+ export declare function buildLoggieSessionId(params: {
9
+ account: Pick<ResolvedLoggieAccount, "accountId">;
10
+ event: LoggieEventEnvelope;
11
+ }): string;
@@ -0,0 +1,13 @@
1
+ const UNSAFE_SESSION_CHARS_RE = /[^a-zA-Z0-9._-]+/g;
2
+ export function meetingConversationId(event) {
3
+ return event.meetingScheduleId ?? event.meetingId ?? event.eventId;
4
+ }
5
+ export function buildLoggieRouteSessionKey(params) {
6
+ return `agent:${params.account.agentId}:loggie:${params.account.accountId}:meeting:${meetingConversationId(params.event)}`;
7
+ }
8
+ export function buildLoggieSessionId(params) {
9
+ return `loggie-${params.account.accountId}-${meetingConversationId(params.event)}`
10
+ .replace(UNSAFE_SESSION_CHARS_RE, "-")
11
+ .replace(/^-+|-+$/g, "")
12
+ .slice(0, 128);
13
+ }
@@ -0,0 +1,3 @@
1
+ import type { PluginRuntime } from "openclaw/plugin-sdk/channel-core";
2
+ declare const setLoggieRuntime: (runtime: PluginRuntime) => void, clearLoggieRuntime: () => void, getOptionalLoggieRuntime: () => PluginRuntime | undefined;
3
+ export { clearLoggieRuntime, getOptionalLoggieRuntime, setLoggieRuntime };
@@ -0,0 +1,6 @@
1
+ import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
2
+ const { setRuntime: setLoggieRuntime, clearRuntime: clearLoggieRuntime, tryGetRuntime: getOptionalLoggieRuntime, } = createPluginRuntimeStore({
3
+ pluginId: "loggie",
4
+ errorMessage: "Loggie runtime not initialized",
5
+ });
6
+ export { clearLoggieRuntime, getOptionalLoggieRuntime, setLoggieRuntime };
@@ -0,0 +1,45 @@
1
+ import type { ResolvedLoggieAccount } from "./account.js";
2
+ export type LoggieRuntimeExtra = {
3
+ connected?: boolean;
4
+ authenticated?: boolean;
5
+ caughtUp?: boolean;
6
+ lastEventId?: string | null;
7
+ lastCursor?: string | null;
8
+ lastSequence?: number | null;
9
+ lastDispatchAt?: number | null;
10
+ lastDeadLetterAt?: number | null;
11
+ lastDeadLetteredEventId?: string | null;
12
+ lastDeadLetteredCursor?: string | null;
13
+ lastDeadLetterReason?: string | null;
14
+ lastDeadLetterAttempts?: number | null;
15
+ };
16
+ export declare const defaultLoggieRuntimeState: {
17
+ accountId: string;
18
+ running: false;
19
+ lastStartAt: null;
20
+ lastStopAt: null;
21
+ lastError: null;
22
+ } & LoggieRuntimeExtra;
23
+ export declare function buildLoggieAccountStatusSnapshot(params: {
24
+ account: ResolvedLoggieAccount;
25
+ runtime?: Record<string, unknown> | null;
26
+ }): Record<string, unknown> & {
27
+ mode: string;
28
+ baseUrl: string;
29
+ agentId: string;
30
+ agentProfileId: string;
31
+ tokenStatus: "available" | "configured_unavailable" | "missing";
32
+ tokenSource: string;
33
+ connected: {};
34
+ authenticated: {};
35
+ caughtUp: {};
36
+ lastEventId: {} | null;
37
+ lastCursor: {} | null;
38
+ lastSequence: {} | null;
39
+ lastDispatchAt: {} | null;
40
+ lastDeadLetterAt: {} | null;
41
+ lastDeadLetteredEventId: {} | null;
42
+ lastDeadLetteredCursor: {} | null;
43
+ lastDeadLetterReason: {} | null;
44
+ lastDeadLetterAttempts: {} | null;
45
+ };
@@ -0,0 +1,45 @@
1
+ import { buildBaseAccountStatusSnapshot, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
2
+ export const defaultLoggieRuntimeState = createDefaultChannelRuntimeState("default", {
3
+ connected: false,
4
+ authenticated: false,
5
+ caughtUp: false,
6
+ lastEventId: null,
7
+ lastCursor: null,
8
+ lastSequence: null,
9
+ lastDispatchAt: null,
10
+ lastDeadLetterAt: null,
11
+ lastDeadLetteredEventId: null,
12
+ lastDeadLetteredCursor: null,
13
+ lastDeadLetterReason: null,
14
+ lastDeadLetterAttempts: null,
15
+ });
16
+ export function buildLoggieAccountStatusSnapshot(params) {
17
+ return buildBaseAccountStatusSnapshot({
18
+ account: {
19
+ accountId: params.account.accountId,
20
+ name: params.account.name,
21
+ enabled: params.account.enabled,
22
+ configured: params.account.configured,
23
+ },
24
+ runtime: params.runtime,
25
+ }, {
26
+ mode: "websocket",
27
+ baseUrl: params.account.baseUrl,
28
+ agentId: params.account.agentId,
29
+ agentProfileId: params.account.agentProfileId,
30
+ tokenStatus: params.account.tokenStatus.status,
31
+ tokenSource: params.account.tokenStatus.source,
32
+ connected: params.runtime?.connected ?? false,
33
+ authenticated: params.runtime?.authenticated ?? false,
34
+ caughtUp: params.runtime?.caughtUp ?? false,
35
+ lastEventId: params.runtime?.lastEventId ?? null,
36
+ lastCursor: params.runtime?.lastCursor ?? null,
37
+ lastSequence: params.runtime?.lastSequence ?? null,
38
+ lastDispatchAt: params.runtime?.lastDispatchAt ?? null,
39
+ lastDeadLetterAt: params.runtime?.lastDeadLetterAt ?? null,
40
+ lastDeadLetteredEventId: params.runtime?.lastDeadLetteredEventId ?? null,
41
+ lastDeadLetteredCursor: params.runtime?.lastDeadLetteredCursor ?? null,
42
+ lastDeadLetterReason: params.runtime?.lastDeadLetterReason ?? null,
43
+ lastDeadLetterAttempts: params.runtime?.lastDeadLetterAttempts ?? null,
44
+ });
45
+ }
package/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";
2
+ import { loggiePlugin } from "./src/channel.js";
3
+ import { loggieEntryConfigSchema } from "./src/config-schema.js";
4
+ import { setLoggieRuntime } from "./src/runtime.js";
5
+
6
+ export default defineChannelPluginEntry({
7
+ id: "loggie",
8
+ name: "Loggie",
9
+ description: "Receives durable Loggie meeting transcript events over WebSocket.",
10
+ plugin: loggiePlugin,
11
+ configSchema: loggieEntryConfigSchema,
12
+ setRuntime: setLoggieRuntime,
13
+ });
@@ -0,0 +1,71 @@
1
+ {
2
+ "id": "loggie",
3
+ "kind": "channel",
4
+ "name": "Loggie",
5
+ "version": "0.1.0",
6
+ "description": "OpenClaw channel plugin for durable Loggie meeting transcript events over WebSocket.",
7
+ "activation": {
8
+ "onStartup": false
9
+ },
10
+ "channels": ["loggie"],
11
+ "channelEnvVars": {
12
+ "loggie": ["LOGGIE_AGENT_TOKEN", "LOGGIE_BASE_URL"]
13
+ },
14
+ "channelConfigs": {
15
+ "loggie": {
16
+ "label": "Loggie",
17
+ "description": "Receives durable Loggie meeting transcript events over WebSocket.",
18
+ "schema": {
19
+ "type": "object",
20
+ "additionalProperties": true,
21
+ "properties": {
22
+ "enabled": { "type": "boolean", "default": true },
23
+ "baseUrl": { "type": "string" },
24
+ "socketPath": { "type": "string", "default": "/api/events/socket" },
25
+ "accountId": { "type": "string", "default": "default" },
26
+ "agentId": { "type": "string", "default": "main" },
27
+ "agentProfileId": { "type": "string" },
28
+ "credentialRef": {},
29
+ "token": { "type": "string" },
30
+ "authHeader": {
31
+ "type": "string",
32
+ "enum": ["authorization", "x-api-key"],
33
+ "default": "authorization"
34
+ },
35
+ "accounts": {
36
+ "type": "object",
37
+ "additionalProperties": { "type": "object" }
38
+ },
39
+ "reconnect": {
40
+ "type": "object",
41
+ "additionalProperties": false,
42
+ "properties": {
43
+ "minMs": { "type": "integer", "minimum": 100, "default": 1000 },
44
+ "maxMs": { "type": "integer", "minimum": 1000, "default": 60000 }
45
+ }
46
+ },
47
+ "heartbeat": {
48
+ "type": "object",
49
+ "additionalProperties": false,
50
+ "properties": {
51
+ "timeoutMs": { "type": "integer", "minimum": 1000, "default": 120000 }
52
+ }
53
+ },
54
+ "transcript": {
55
+ "type": "object",
56
+ "additionalProperties": false,
57
+ "properties": {
58
+ "activation": { "type": "string", "enum": ["final-only"], "default": "final-only" },
59
+ "debounceMs": { "type": "integer", "minimum": 0, "default": 5000 }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+ },
66
+ "configSchema": {
67
+ "type": "object",
68
+ "additionalProperties": false,
69
+ "properties": {}
70
+ }
71
+ }
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "@loggie-ai/openclaw-plugin",
3
+ "version": "0.1.0",
4
+ "description": "OpenClaw channel plugin for Loggie meeting transcript events.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "README.md",
16
+ "index.ts",
17
+ "setup-entry.ts",
18
+ "src/",
19
+ "dist/",
20
+ "openclaw.plugin.json",
21
+ "plugin-inspector.config.json"
22
+ ],
23
+ "scripts": {
24
+ "clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
25
+ "build": "npm run clean && tsc -p tsconfig.build.json",
26
+ "check": "tsc -p tsconfig.json --noEmit",
27
+ "plugin:inspect": "plugin-inspector check --config plugin-inspector.config.json --no-openclaw",
28
+ "plugin:inspect:runtime": "plugin-inspector check --config plugin-inspector.config.json --no-openclaw --runtime --mock-sdk --allow-execute",
29
+ "test": "vitest run",
30
+ "preflight": "npm run check && npm test && npm run build && npm run plugin:inspect && npm run plugin:inspect:runtime"
31
+ },
32
+ "openclaw": {
33
+ "extensions": [
34
+ "./index.ts"
35
+ ],
36
+ "runtimeExtensions": [
37
+ "./dist/index.js"
38
+ ],
39
+ "setupEntry": "./setup-entry.ts",
40
+ "channel": {
41
+ "id": "loggie",
42
+ "label": "Loggie",
43
+ "selectionLabel": "Loggie",
44
+ "blurb": "Receives durable Loggie meeting transcript events over WebSocket.",
45
+ "docsPath": "/plugins/loggie"
46
+ },
47
+ "startup": {
48
+ "deferConfiguredChannelFullLoadUntilAfterListen": true
49
+ },
50
+ "install": {
51
+ "npmSpec": "@loggie-ai/openclaw-plugin",
52
+ "defaultChoice": "npm",
53
+ "minHostVersion": ">=2026.6.10"
54
+ },
55
+ "compat": {
56
+ "pluginApi": ">=2026.6.10",
57
+ "minGatewayVersion": ">=2026.6.10"
58
+ },
59
+ "build": {
60
+ "openclawVersion": "2026.6.10",
61
+ "pluginSdkVersion": "2026.6.10"
62
+ }
63
+ },
64
+ "keywords": [
65
+ "openclaw",
66
+ "openclaw-plugin",
67
+ "channel",
68
+ "loggie"
69
+ ],
70
+ "license": "MIT",
71
+ "engines": {
72
+ "node": ">=22"
73
+ },
74
+ "peerDependencies": {
75
+ "openclaw": ">=2026.6.10"
76
+ },
77
+ "peerDependenciesMeta": {
78
+ "openclaw": {
79
+ "optional": true
80
+ }
81
+ },
82
+ "dependencies": {
83
+ "ws": "^8.18.3",
84
+ "zod": "^3.25.76"
85
+ },
86
+ "devDependencies": {
87
+ "@openclaw/plugin-inspector": "^0.3.10",
88
+ "@types/node": "^22.15.29",
89
+ "@types/ws": "^8.18.1",
90
+ "typescript": "^5.9.2",
91
+ "vitest": "^3.2.4"
92
+ }
93
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": 1,
3
+ "plugin": {
4
+ "id": "loggie",
5
+ "priority": "medium",
6
+ "seams": ["manifest-contract", "sdk-surface", "channel"],
7
+ "sourceRoot": ".",
8
+ "expect": {
9
+ "registrations": ["registerChannel"]
10
+ }
11
+ },
12
+ "capture": {
13
+ "mockSdk": true
14
+ }
15
+ }
package/setup-entry.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";
2
+ import { loggiePlugin } from "./src/channel.js";
3
+
4
+ export default defineSetupPluginEntry(loggiePlugin);