@botcord/botcord 0.1.3-beta.1 → 0.1.4-beta.20260325025643

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/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * @botcord/botcord — OpenClaw plugin for BotCord A2A messaging protocol.
3
3
  */
4
- import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
5
4
  import { botCordPlugin } from "./src/channel.js";
6
5
  import { setBotCordRuntime, setConfigGetter } from "./src/runtime.js";
7
6
  import { createMessagingTool, createUploadTool } from "./src/tools/messaging.js";
@@ -14,9 +13,11 @@ import { createPaymentTool } from "./src/tools/payment.js";
14
13
  import { createSubscriptionTool } from "./src/tools/subscription.js";
15
14
  import { createNotifyTool } from "./src/tools/notify.js";
16
15
  import { createBindTool } from "./src/tools/bind.js";
16
+ import { createRegisterTool } from "./src/tools/register.js";
17
17
  import { createHealthcheckCommand } from "./src/commands/healthcheck.js";
18
18
  import { createTokenCommand } from "./src/commands/token.js";
19
19
  import { createBindCommand } from "./src/commands/bind.js";
20
+ import { createEnvCommand } from "./src/commands/env.js";
20
21
  import { createRegisterCli } from "./src/commands/register.js";
21
22
  import {
22
23
  buildBotCordLoopRiskPrompt,
@@ -26,17 +27,18 @@ import {
26
27
  shouldRunBotCordLoopRiskCheck,
27
28
  } from "./src/loop-risk.js";
28
29
 
29
- export default defineChannelPluginEntry({
30
+ // Inline replacement for defineChannelPluginEntry from openclaw/plugin-sdk/core.
31
+ // Avoids missing dist artifacts in npm-installed openclaw (see openclaw#53685).
32
+ export default {
30
33
  id: "botcord",
31
34
  name: "BotCord",
32
35
  description: "BotCord A2A messaging protocol — secure agent-to-agent communication with Ed25519 signing",
33
- plugin: botCordPlugin,
36
+ register(api: any) {
37
+ setBotCordRuntime(api.runtime);
38
+ api.registerChannel({ plugin: botCordPlugin });
34
39
 
35
- setRuntime(runtime) {
36
- setBotCordRuntime(runtime);
37
- },
40
+ if (api.registrationMode !== "full") return;
38
41
 
39
- registerFull(api) {
40
42
  setConfigGetter(() => api.config);
41
43
 
42
44
  // Agent tools — `as any` needed until tool execute() return types are
@@ -52,9 +54,10 @@ export default defineChannelPluginEntry({
52
54
  api.registerTool(createSubscriptionTool() as any);
53
55
  api.registerTool(createNotifyTool() as any);
54
56
  api.registerTool(createBindTool() as any);
57
+ api.registerTool(createRegisterTool() as any);
55
58
 
56
59
  // Hooks
57
- api.on("after_tool_call", async (event, ctx) => {
60
+ api.on("after_tool_call", async (event: any, ctx: any) => {
58
61
  if (ctx.toolName !== "botcord_send") return;
59
62
  if (!didBotCordSendSucceed(event.result, event.error)) return;
60
63
  recordBotCordOutboundText({
@@ -63,7 +66,7 @@ export default defineChannelPluginEntry({
63
66
  });
64
67
  });
65
68
 
66
- api.on("before_prompt_build", async (event, ctx) => {
69
+ api.on("before_prompt_build", async (event: any, ctx: any) => {
67
70
  if (!shouldRunBotCordLoopRiskCheck({
68
71
  channelId: ctx.channelId,
69
72
  prompt: event.prompt,
@@ -82,7 +85,7 @@ export default defineChannelPluginEntry({
82
85
  return { prependContext };
83
86
  }, { priority: 10 });
84
87
 
85
- api.on("session_end", async (_event, ctx) => {
88
+ api.on("session_end", async (_event: any, ctx: any) => {
86
89
  clearBotCordLoopRiskSession(ctx.sessionKey);
87
90
  });
88
91
 
@@ -90,12 +93,13 @@ export default defineChannelPluginEntry({
90
93
  api.registerCommand(createHealthcheckCommand());
91
94
  api.registerCommand(createTokenCommand());
92
95
  api.registerCommand(createBindCommand());
96
+ api.registerCommand(createEnvCommand());
93
97
 
94
98
  // CLI
95
99
  const registerCli = createRegisterCli();
96
100
  api.registerCli(registerCli.setup, { commands: registerCli.commands });
97
101
  },
98
- });
102
+ };
99
103
 
100
104
  export { TopicTracker } from "./src/topic-tracker.js";
101
105
  export type { TopicState, TopicInfo } from "./src/topic-tracker.js";
@@ -2,7 +2,7 @@
2
2
  "id": "botcord",
3
3
  "name": "BotCord",
4
4
  "description": "Secure agent-to-agent messaging via the BotCord A2A protocol (Ed25519 signed envelopes)",
5
- "version": "0.1.3-beta.1",
5
+ "version": "0.1.4-beta.20260325025643",
6
6
  "channels": [
7
7
  "botcord"
8
8
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botcord/botcord",
3
- "version": "0.1.3-beta.1",
3
+ "version": "0.1.4-beta.20260325025643",
4
4
  "description": "OpenClaw channel plugin for BotCord A2A messaging protocol (Ed25519 signed envelopes)",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
package/setup-entry.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // setup-entry.ts — lightweight entry for onboarding/config (no heavy deps like ws)
2
- import { defineSetupPluginEntry } from "openclaw/plugin-sdk/core";
3
2
  import { botCordPlugin } from "./src/channel.js";
4
3
 
5
- export default defineSetupPluginEntry(botCordPlugin);
4
+ // Inline replacement for defineSetupPluginEntry (just returns { plugin }).
5
+ export default { plugin: botCordPlugin };
package/src/channel.ts CHANGED
@@ -4,11 +4,35 @@
4
4
  * security, messaging, and status adapters.
5
5
  */
6
6
  import type { ChannelPlugin, OpenClawConfig as ClawdbotConfig } from "openclaw/plugin-sdk/core";
7
- import {
8
- buildBaseChannelStatusSummary,
9
- createDefaultChannelRuntimeState,
10
- } from "openclaw/plugin-sdk/status-helpers";
11
- import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
7
+ // Inlined from openclaw/plugin-sdk/status-helpers and account-id to avoid
8
+ // missing dist artifacts in npm-installed openclaw (see openclaw#53685).
9
+ const DEFAULT_ACCOUNT_ID = "default";
10
+
11
+ function createDefaultChannelRuntimeState(accountId: string) {
12
+ return {
13
+ accountId,
14
+ running: false as const,
15
+ lastStartAt: null,
16
+ lastStopAt: null,
17
+ lastError: null,
18
+ };
19
+ }
20
+
21
+ function buildBaseChannelStatusSummary(snapshot: {
22
+ configured?: boolean | null;
23
+ running?: boolean | null;
24
+ lastStartAt?: number | null;
25
+ lastStopAt?: number | null;
26
+ lastError?: string | null;
27
+ }) {
28
+ return {
29
+ configured: snapshot.configured ?? false,
30
+ running: snapshot.running ?? false,
31
+ lastStartAt: snapshot.lastStartAt ?? null,
32
+ lastStopAt: snapshot.lastStopAt ?? null,
33
+ lastError: snapshot.lastError ?? null,
34
+ };
35
+ }
12
36
  import {
13
37
  resolveChannelConfig,
14
38
  resolveAccounts,
@@ -0,0 +1,108 @@
1
+ /**
2
+ * /botcord_env — View or switch the BotCord Hub environment.
3
+ *
4
+ * Usage:
5
+ * /botcord_env — show current hub URL and environment
6
+ * /botcord_env stable — switch to stable (api.botcord.chat)
7
+ * /botcord_env beta — switch to beta (preview.botcord.chat)
8
+ * /botcord_env test — switch to test (test.botcord.chat)
9
+ * /botcord_env <url> — switch to a custom hub URL
10
+ *
11
+ * Changes are written to the credentials file. Restart gateway to take effect.
12
+ */
13
+ import { ENV_PRESETS } from "../constants.js";
14
+ import {
15
+ resolveAccountConfig,
16
+ isAccountConfigured,
17
+ } from "../config.js";
18
+ import {
19
+ loadStoredCredentials,
20
+ writeCredentialsFile,
21
+ } from "../credentials.js";
22
+ import { normalizeAndValidateHubUrl } from "../hub-url.js";
23
+ import { getConfig as getAppConfig } from "../runtime.js";
24
+
25
+ function resolveEnvLabel(hubUrl: string): string | null {
26
+ for (const [name, url] of Object.entries(ENV_PRESETS)) {
27
+ if (hubUrl === url) return name;
28
+ }
29
+ return null;
30
+ }
31
+
32
+ export function createEnvCommand() {
33
+ return {
34
+ name: "botcord_env",
35
+ description: "View or switch the BotCord Hub environment (stable/beta/test or custom URL).",
36
+ acceptsArgs: true,
37
+ requireAuth: true,
38
+ handler: async (ctx: any) => {
39
+ const cfg = getAppConfig();
40
+ if (!cfg) {
41
+ return { text: "[FAIL] No OpenClaw configuration available" };
42
+ }
43
+
44
+ const acct = resolveAccountConfig(cfg);
45
+ if (!isAccountConfigured(acct)) {
46
+ return { text: "[FAIL] BotCord is not fully configured (need hubUrl, agentId, keyId, privateKey)" };
47
+ }
48
+
49
+ const arg = (ctx.args || "").trim();
50
+
51
+ // ── No argument: show current environment ──
52
+ if (!arg) {
53
+ const current = acct.hubUrl || "(not set)";
54
+ const label = acct.hubUrl ? resolveEnvLabel(acct.hubUrl) : null;
55
+ const envDisplay = label ? ` (${label})` : "";
56
+ const presetList = Object.entries(ENV_PRESETS)
57
+ .map(([name, url]) => ` ${name} → ${url}`)
58
+ .join("\n");
59
+ return {
60
+ text: [
61
+ `Current hub: ${current}${envDisplay}`,
62
+ "",
63
+ "Available environments:",
64
+ presetList,
65
+ "",
66
+ "Usage: /botcord_env <stable|beta|test|URL>",
67
+ ].join("\n"),
68
+ };
69
+ }
70
+
71
+ // ── Resolve target URL ──
72
+ const targetUrl = ENV_PRESETS[arg] || arg;
73
+
74
+ let normalizedUrl: string;
75
+ try {
76
+ normalizedUrl = normalizeAndValidateHubUrl(targetUrl);
77
+ } catch (err: any) {
78
+ return { text: `[FAIL] Invalid hub URL: ${err.message}` };
79
+ }
80
+
81
+ // ── Check if already on this URL ──
82
+ if (acct.hubUrl === normalizedUrl) {
83
+ const label = resolveEnvLabel(normalizedUrl);
84
+ const envDisplay = label ? ` (${label})` : "";
85
+ return { text: `Already on ${normalizedUrl}${envDisplay}. No change needed.` };
86
+ }
87
+
88
+ // ── Write to credentials file ──
89
+ if (!acct.credentialsFile) {
90
+ return { text: "[FAIL] No credentials file configured — cannot persist hub URL change" };
91
+ }
92
+
93
+ try {
94
+ const creds = loadStoredCredentials(acct.credentialsFile);
95
+ creds.hubUrl = normalizedUrl;
96
+ writeCredentialsFile(acct.credentialsFile, creds);
97
+ } catch (err: any) {
98
+ return { text: `[FAIL] Could not update credentials file: ${err.message}` };
99
+ }
100
+
101
+ const label = resolveEnvLabel(normalizedUrl);
102
+ const envDisplay = label ? ` (${label})` : "";
103
+ return {
104
+ text: `[OK] Hub URL updated to ${normalizedUrl}${envDisplay}. Restart gateway to take effect.`,
105
+ };
106
+ },
107
+ };
108
+ }
package/src/constants.ts CHANGED
@@ -17,3 +17,10 @@ const HUB_URLS: Record<ReleaseChannel, string> = {
17
17
  };
18
18
 
19
19
  export const DEFAULT_HUB = HUB_URLS[RELEASE_CHANNEL];
20
+
21
+ /** Named environment presets for /botcord_env. */
22
+ export const ENV_PRESETS: Record<string, string> = {
23
+ stable: "https://api.botcord.chat",
24
+ beta: "https://preview.botcord.chat",
25
+ test: "https://test.botcord.chat",
26
+ };
package/src/inbound.ts CHANGED
@@ -5,7 +5,20 @@
5
5
  import { getBotCordRuntime } from "./runtime.js";
6
6
  import { resolveAccountConfig } from "./config.js";
7
7
  import { buildSessionKey } from "./session-key.js";
8
- import { loadSessionStore } from "openclaw/plugin-sdk/mattermost";
8
+ import { readFileSync } from "node:fs";
9
+
10
+ // Simplified inline replacement for loadSessionStore from openclaw/plugin-sdk/mattermost.
11
+ // Avoids missing dist artifacts in npm-installed openclaw (see openclaw#53685).
12
+ function loadSessionStore(storePath: string): Record<string, any> {
13
+ try {
14
+ const raw = readFileSync(storePath, "utf-8");
15
+ if (!raw) return {};
16
+ const parsed = JSON.parse(raw);
17
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
18
+ } catch {
19
+ return {};
20
+ }
21
+ }
9
22
  import { sanitizeUntrustedContent, sanitizeSenderName } from "./sanitize.js";
10
23
  import { BotCordClient } from "./client.js";
11
24
  import { createBotCordReplyDispatcher } from "./reply-dispatcher.js";
@@ -0,0 +1,67 @@
1
+ /**
2
+ * botcord_register — Register a new BotCord agent identity via tool call.
3
+ */
4
+ import { registerAgent } from "../commands/register.js";
5
+ import { getConfig as getAppConfig } from "../runtime.js";
6
+ import { DEFAULT_HUB } from "../constants.js";
7
+
8
+ export function createRegisterTool() {
9
+ return {
10
+ name: "botcord_register",
11
+ label: "Register Agent",
12
+ description:
13
+ "Register a new BotCord agent: generate an Ed25519 keypair, register with the Hub, and save credentials locally.",
14
+ parameters: {
15
+ type: "object" as const,
16
+ properties: {
17
+ name: {
18
+ type: "string" as const,
19
+ description: "Agent display name",
20
+ },
21
+ bio: {
22
+ type: "string" as const,
23
+ description: "Agent bio/description (optional)",
24
+ },
25
+ hub: {
26
+ type: "string" as const,
27
+ description: `Hub URL (defaults to ${DEFAULT_HUB})`,
28
+ },
29
+ new_identity: {
30
+ type: "boolean" as const,
31
+ description: "Generate a fresh keypair instead of reusing existing credentials (default false)",
32
+ },
33
+ },
34
+ required: ["name"],
35
+ },
36
+ execute: async (toolCallId: any, args: any, signal?: any, onUpdate?: any) => {
37
+ if (!args.name) {
38
+ return { error: "name is required" };
39
+ }
40
+
41
+ const cfg = getAppConfig();
42
+ if (!cfg) return { error: "No configuration available" };
43
+
44
+ try {
45
+ const result = await registerAgent({
46
+ name: args.name,
47
+ bio: args.bio || "",
48
+ hub: args.hub || DEFAULT_HUB,
49
+ config: cfg,
50
+ newIdentity: args.new_identity ?? false,
51
+ });
52
+ return {
53
+ ok: true,
54
+ agent_id: result.agentId,
55
+ key_id: result.keyId,
56
+ display_name: result.displayName,
57
+ hub: result.hub,
58
+ credentials_file: result.credentialsFile,
59
+ claim_url: result.claimUrl,
60
+ note: "Restart OpenClaw to activate: openclaw gateway restart",
61
+ };
62
+ } catch (err: any) {
63
+ return { error: `Registration failed: ${err.message}` };
64
+ }
65
+ },
66
+ };
67
+ }