@tloncorp/openclaw 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 (63) hide show
  1. package/README.md +174 -0
  2. package/dist/index.js +190 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/src/account-fields.js +17 -0
  5. package/dist/src/account-fields.js.map +1 -0
  6. package/dist/src/actions.js +164 -0
  7. package/dist/src/actions.js.map +1 -0
  8. package/dist/src/channel.js +400 -0
  9. package/dist/src/channel.js.map +1 -0
  10. package/dist/src/config-schema.js +55 -0
  11. package/dist/src/config-schema.js.map +1 -0
  12. package/dist/src/monitor/approval.js +194 -0
  13. package/dist/src/monitor/approval.js.map +1 -0
  14. package/dist/src/monitor/discovery.js +64 -0
  15. package/dist/src/monitor/discovery.js.map +1 -0
  16. package/dist/src/monitor/history.js +158 -0
  17. package/dist/src/monitor/history.js.map +1 -0
  18. package/dist/src/monitor/index.js +1940 -0
  19. package/dist/src/monitor/index.js.map +1 -0
  20. package/dist/src/monitor/media.js +128 -0
  21. package/dist/src/monitor/media.js.map +1 -0
  22. package/dist/src/monitor/processed-messages.js +38 -0
  23. package/dist/src/monitor/processed-messages.js.map +1 -0
  24. package/dist/src/monitor/utils.js +283 -0
  25. package/dist/src/monitor/utils.js.map +1 -0
  26. package/dist/src/onboarding.js +178 -0
  27. package/dist/src/onboarding.js.map +1 -0
  28. package/dist/src/runtime.js +11 -0
  29. package/dist/src/runtime.js.map +1 -0
  30. package/dist/src/settings.js +305 -0
  31. package/dist/src/settings.js.map +1 -0
  32. package/dist/src/targets.js +85 -0
  33. package/dist/src/targets.js.map +1 -0
  34. package/dist/src/types.js +79 -0
  35. package/dist/src/types.js.map +1 -0
  36. package/dist/src/urbit/api-client.js +104 -0
  37. package/dist/src/urbit/api-client.js.map +1 -0
  38. package/dist/src/urbit/auth.js +35 -0
  39. package/dist/src/urbit/auth.js.map +1 -0
  40. package/dist/src/urbit/base-url.js +45 -0
  41. package/dist/src/urbit/base-url.js.map +1 -0
  42. package/dist/src/urbit/channel-ops.js +136 -0
  43. package/dist/src/urbit/channel-ops.js.map +1 -0
  44. package/dist/src/urbit/context.js +42 -0
  45. package/dist/src/urbit/context.js.map +1 -0
  46. package/dist/src/urbit/errors.js +36 -0
  47. package/dist/src/urbit/errors.js.map +1 -0
  48. package/dist/src/urbit/fetch.js +23 -0
  49. package/dist/src/urbit/fetch.js.map +1 -0
  50. package/dist/src/urbit/foreigns.js +6 -0
  51. package/dist/src/urbit/foreigns.js.map +1 -0
  52. package/dist/src/urbit/http-poke.js +56 -0
  53. package/dist/src/urbit/http-poke.js.map +1 -0
  54. package/dist/src/urbit/send.js +208 -0
  55. package/dist/src/urbit/send.js.map +1 -0
  56. package/dist/src/urbit/sse-client.js +453 -0
  57. package/dist/src/urbit/sse-client.js.map +1 -0
  58. package/dist/src/urbit/story.js +286 -0
  59. package/dist/src/urbit/story.js.map +1 -0
  60. package/dist/src/urbit/upload.js +51 -0
  61. package/dist/src/urbit/upload.js.map +1 -0
  62. package/openclaw.plugin.json +10 -0
  63. package/package.json +84 -0
package/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # OpenClaw Tlon Plugin
2
+
3
+ Tlon/Urbit channel plugin for [OpenClaw](https://github.com/openclaw/openclaw). Enables your AI agent to communicate via Tlon DMs and group channels.
4
+
5
+ ## Features
6
+
7
+ - **DMs**: Receive and respond to direct messages
8
+ - **Group Channels**: Participate in group chats (mention-triggered or open mode)
9
+ - **Thread Replies**: Support for threaded conversations
10
+ - **Rich Content**: Images, links, and formatted text
11
+ - **Ship Authorization**: Allowlist ships for DM access
12
+ - **Channel Authorization**: Per-channel ship allowlists with open/restricted modes
13
+ - **Approval System**: Approve/deny new DMs, channel mentions, and group invites via DM
14
+ - **Settings Store**: Hot-reload config via Urbit settings-store (no restart needed)
15
+ - **Auto-Discovery**: Automatically monitors all channels in joined groups
16
+ - **Cite Resolution**: Parse and fetch quoted message content
17
+
18
+ ## Installation
19
+
20
+ This plugin is included with OpenClaw. Enable it in your config:
21
+
22
+ ```yaml
23
+ channels:
24
+ tlon:
25
+ enabled: true
26
+ ship: "~your-ship"
27
+ url: "https://your-ship.tlon.network"
28
+ code: "your-access-code"
29
+ ```
30
+
31
+ ### Full Configuration Example
32
+
33
+ ```yaml
34
+ channels:
35
+ tlon:
36
+ enabled: true
37
+ ship: "~your-ship"
38
+ url: "https://your-ship.tlon.network"
39
+ code: "your-access-code"
40
+
41
+ # Owner receives approval requests and can manage the bot
42
+ ownerShip: "~your-main-ship"
43
+
44
+ # Ships allowed to DM the bot directly
45
+ dmAllowlist:
46
+ - "~trusted-friend"
47
+ - "~another-ship"
48
+
49
+ # Auto-accept settings
50
+ autoAcceptDmInvites: true # Accept DMs from ships in dmAllowlist
51
+ autoAcceptGroupInvites: false # Require approval for group invites
52
+
53
+ # Channel discovery
54
+ autoDiscoverChannels: true # Monitor all channels in joined groups
55
+ groupChannels: # Additional channels to monitor explicitly
56
+ - "chat/~host-ship/channel-name"
57
+
58
+ # Per-channel authorization
59
+ authorization:
60
+ channelRules:
61
+ "chat/~host/public-channel":
62
+ mode: "open" # Anyone can interact
63
+ "chat/~host/private-channel":
64
+ mode: "restricted"
65
+ allowedShips:
66
+ - "~specific-ship"
67
+
68
+ # Ships authorized by default for restricted channels
69
+ defaultAuthorizedShips:
70
+ - "~always-allowed"
71
+
72
+ # Show model info in responses
73
+ showModelSignature: false
74
+ ```
75
+
76
+ ## Approval System
77
+
78
+ The approval system lets you control who can interact with your bot. When `ownerShip` is configured, you'll receive DM notifications for:
79
+
80
+ - **DM requests** from ships not on your `dmAllowlist`
81
+ - **Channel mentions** from ships not authorized for that channel
82
+ - **Group invites** (if `autoAcceptGroupInvites` is false)
83
+
84
+ ### Usage
85
+
86
+ When someone not on the allowlist tries to interact, you'll receive a DM like:
87
+
88
+ ```
89
+ New DM request from ~sampel-palnet:
90
+ "Hello, I'd like to chat with your bot..."
91
+
92
+ Reply "approve", "deny", or "block" (ID: dm-1234567890-abc)
93
+ ```
94
+
95
+ - **approve**: Allow the interaction and add to allowlist. Original message is processed.
96
+ - **deny**: Reject silently. Ship can try again later.
97
+ - **block**: Permanently block using Tlon's native blocking.
98
+
99
+ ### Admin Commands
100
+
101
+ The owner can send these commands via DM:
102
+
103
+ | Command | Description |
104
+ |---------|-------------|
105
+ | `blocked` | List all blocked ships |
106
+ | `pending` | List pending approval requests |
107
+ | `unblock ~ship` | Unblock a ship |
108
+
109
+ ## Bundled Skill
110
+
111
+ This plugin bundles [@tloncorp/tlon-skill](https://www.npmjs.com/package/@tloncorp/tlon-skill) which provides CLI commands for:
112
+
113
+ - Contacts and profile management
114
+ - Channel listing and history
115
+ - Group administration
116
+ - Message posting and reactions
117
+ - Settings management
118
+
119
+ The skill is automatically available to your agent. For standalone usage, see the [tlon-skill repo](https://github.com/tloncorp/tlon-skill).
120
+
121
+ ## Documentation
122
+
123
+ Full documentation: https://docs.openclaw.ai/channels/tlon
124
+
125
+ ## Development
126
+
127
+ ### Prerequisites
128
+
129
+ - Docker
130
+ - [GitHub CLI](https://cli.github.com/) (`gh`) authenticated with tloncorp access
131
+ - A local Urbit ship (e.g., on `http://localhost:8080`)
132
+ - Anthropic API key (or OpenRouter for alternative models)
133
+
134
+ ### Quick Start
135
+
136
+ ```bash
137
+ # 1. Clone this repo
138
+ gh repo clone tloncorp/openclaw-tlon
139
+ cd openclaw-tlon
140
+
141
+ # 2. Run setup (clones api-beta, creates .env)
142
+ ./dev/setup.sh
143
+
144
+ # 3. Edit .env with your credentials
145
+ # - ANTHROPIC_API_KEY or OPENROUTER_API_KEY
146
+ # - TLON_URL: http://host.docker.internal:<port> (not localhost!)
147
+ # - TLON_SHIP, TLON_CODE
148
+ # - TLON_DM_ALLOWLIST, TLON_OWNER_SHIP
149
+
150
+ # 4. Start dev environment (loads OPENCLAW_GATEWAY_PORT from root .env)
151
+ docker compose --env-file .env -f dev/docker-compose.yml up --build
152
+
153
+ # 5. Access OpenClaw at http://localhost:${OPENCLAW_GATEWAY_PORT:-18789}
154
+ ```
155
+
156
+ ### Directory Structure
157
+
158
+ ```
159
+ parent/
160
+ ├── api-beta/ # @tloncorp/api - shared API library (cloned by setup)
161
+ └── openclaw-tlon/ # This repo
162
+ ```
163
+
164
+ The tlon-skill is installed via npm and doesn't need to be cloned separately.
165
+
166
+ ### Making Changes
167
+
168
+ 1. Edit code in either repo
169
+ 2. Restart container: `docker compose --env-file .env -f dev/docker-compose.yml up --build`
170
+ 3. For faster iteration, run OpenClaw directly on host with npm link
171
+
172
+ ## License
173
+
174
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,190 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
6
+ import { tlonPlugin } from "./src/channel.js";
7
+ import { setTlonRuntime } from "./src/runtime.js";
8
+ import { resolveTlonAccount } from "./src/types.js";
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ // Whitelist of allowed tlon subcommands
11
+ const ALLOWED_TLON_COMMANDS = new Set([
12
+ "activity",
13
+ "channels",
14
+ "contacts",
15
+ "groups",
16
+ "messages",
17
+ "dms",
18
+ "posts",
19
+ "notebook",
20
+ "settings",
21
+ "help",
22
+ "version",
23
+ ]);
24
+ /**
25
+ * Find the tlon binary from the skill package
26
+ */
27
+ function findTlonBinary() {
28
+ // Check in node_modules/.bin
29
+ const skillBin = join(__dirname, "node_modules", ".bin", "tlon");
30
+ console.log(`[tlon] Checking for binary at: ${skillBin}, exists: ${existsSync(skillBin)}`);
31
+ if (existsSync(skillBin))
32
+ return skillBin;
33
+ // Check for platform-specific binary directly
34
+ const platform = process.platform;
35
+ const arch = process.arch;
36
+ const platformPkg = `@tloncorp/tlon-skill-${platform}-${arch}`;
37
+ const platformBin = join(__dirname, "node_modules", platformPkg, "tlon");
38
+ console.log(`[tlon] Checking for platform binary at: ${platformBin}, exists: ${existsSync(platformBin)}`);
39
+ if (existsSync(platformBin))
40
+ return platformBin;
41
+ // Fallback to PATH
42
+ console.log(`[tlon] Falling back to PATH lookup for 'tlon'`);
43
+ return "tlon";
44
+ }
45
+ /**
46
+ * Shell-like argument splitter that respects quotes
47
+ */
48
+ function shellSplit(str) {
49
+ const args = [];
50
+ let cur = "";
51
+ let inDouble = false;
52
+ let inSingle = false;
53
+ let escape = false;
54
+ for (const ch of str) {
55
+ if (escape) {
56
+ cur += ch;
57
+ escape = false;
58
+ continue;
59
+ }
60
+ if (ch === "\\" && !inSingle) {
61
+ escape = true;
62
+ continue;
63
+ }
64
+ if (ch === '"' && !inSingle) {
65
+ inDouble = !inDouble;
66
+ continue;
67
+ }
68
+ if (ch === "'" && !inDouble) {
69
+ inSingle = !inSingle;
70
+ continue;
71
+ }
72
+ if (/\s/.test(ch) && !inDouble && !inSingle) {
73
+ if (cur) {
74
+ args.push(cur);
75
+ cur = "";
76
+ }
77
+ continue;
78
+ }
79
+ cur += ch;
80
+ }
81
+ if (cur)
82
+ args.push(cur);
83
+ return args;
84
+ }
85
+ /**
86
+ * Run the tlon command and return the result
87
+ */
88
+ function runTlonCommand(binary, args, credentials) {
89
+ return new Promise((resolve, reject) => {
90
+ // Build environment with Tlon credentials if provided
91
+ const env = { ...process.env };
92
+ if (credentials) {
93
+ env.URBIT_URL = credentials.url;
94
+ env.URBIT_SHIP = credentials.ship;
95
+ env.URBIT_CODE = credentials.code;
96
+ }
97
+ const child = spawn(binary, args, { env });
98
+ let stdout = "";
99
+ let stderr = "";
100
+ child.stdout.on("data", (data) => {
101
+ stdout += data.toString();
102
+ });
103
+ child.stderr.on("data", (data) => {
104
+ stderr += data.toString();
105
+ });
106
+ child.on("error", (err) => {
107
+ reject(new Error(`Failed to run tlon: ${err.message}`));
108
+ });
109
+ child.on("close", (code) => {
110
+ if (code !== 0) {
111
+ reject(new Error(stderr || `tlon exited with code ${code}`));
112
+ }
113
+ else {
114
+ resolve(stdout);
115
+ }
116
+ });
117
+ });
118
+ }
119
+ const plugin = {
120
+ id: "tlon",
121
+ name: "Tlon",
122
+ description: "Tlon/Urbit channel plugin",
123
+ configSchema: emptyPluginConfigSchema(),
124
+ register(api) {
125
+ setTlonRuntime(api.runtime);
126
+ api.registerChannel({ plugin: tlonPlugin });
127
+ // Register the tlon tool
128
+ const tlonBinary = findTlonBinary();
129
+ api.logger.info(`[tlon] Registering tlon tool, binary: ${tlonBinary}`);
130
+ // Capture credentials from config at registration time
131
+ const account = resolveTlonAccount(api.config);
132
+ const credentials = account.configured && account.url && account.ship && account.code
133
+ ? { url: account.url, ship: account.ship, code: account.code }
134
+ : undefined;
135
+ if (credentials) {
136
+ api.logger.info(`[tlon] Credentials available for ${account.ship}`);
137
+ }
138
+ else {
139
+ api.logger.warn(`[tlon] No credentials configured - tlon tool will rely on env vars`);
140
+ }
141
+ api.registerTool({
142
+ name: "tlon",
143
+ label: "Tlon CLI",
144
+ description: "Tlon/Urbit API operations: activity, channels, contacts, groups, messages, dms, posts, notebook, settings. " +
145
+ "Examples: 'activity mentions --limit 10', 'channels groups', 'contacts self', 'groups list'",
146
+ parameters: {
147
+ type: "object",
148
+ properties: {
149
+ command: {
150
+ type: "string",
151
+ description: "The tlon command and arguments. " +
152
+ "Examples: 'activity mentions --limit 10', 'contacts get ~sampel-palnet', 'groups list'",
153
+ },
154
+ },
155
+ required: ["command"],
156
+ },
157
+ async execute(_id, params) {
158
+ try {
159
+ const args = shellSplit(params.command);
160
+ // Validate first argument is a whitelisted tlon subcommand
161
+ const subcommand = args[0];
162
+ if (!ALLOWED_TLON_COMMANDS.has(subcommand)) {
163
+ return {
164
+ content: [
165
+ {
166
+ type: "text",
167
+ text: `Error: Unknown tlon subcommand '${subcommand}'. Allowed: ${[...ALLOWED_TLON_COMMANDS].join(", ")}`,
168
+ },
169
+ ],
170
+ details: { error: true },
171
+ };
172
+ }
173
+ const output = await runTlonCommand(tlonBinary, args, credentials);
174
+ return {
175
+ content: [{ type: "text", text: output }],
176
+ details: undefined,
177
+ };
178
+ }
179
+ catch (error) {
180
+ return {
181
+ content: [{ type: "text", text: `Error: ${error.message}` }],
182
+ details: { error: true },
183
+ };
184
+ }
185
+ },
186
+ });
187
+ },
188
+ };
189
+ export default plugin;
190
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export function buildTlonAccountFields(input) {
2
+ return {
3
+ ...(input.ship ? { ship: input.ship } : {}),
4
+ ...(input.url ? { url: input.url } : {}),
5
+ ...(input.code ? { code: input.code } : {}),
6
+ ...(typeof input.allowPrivateNetwork === "boolean"
7
+ ? { allowPrivateNetwork: input.allowPrivateNetwork }
8
+ : {}),
9
+ ...(input.groupChannels ? { groupChannels: input.groupChannels } : {}),
10
+ ...(input.dmAllowlist ? { dmAllowlist: input.dmAllowlist } : {}),
11
+ ...(typeof input.autoDiscoverChannels === "boolean"
12
+ ? { autoDiscoverChannels: input.autoDiscoverChannels }
13
+ : {}),
14
+ ...(input.ownerShip ? { ownerShip: input.ownerShip } : {}),
15
+ };
16
+ }
17
+ //# sourceMappingURL=account-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-fields.js","sourceRoot":"","sources":["../../src/account-fields.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,sBAAsB,CAAC,KAA6B;IAClE,OAAO;QACL,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,GAAG,CAAC,OAAO,KAAK,CAAC,mBAAmB,KAAK,SAAS;YAChD,CAAC,CAAC,EAAE,mBAAmB,EAAE,KAAK,CAAC,mBAAmB,EAAE;YACpD,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,OAAO,KAAK,CAAC,oBAAoB,KAAK,SAAS;YACjD,CAAC,CAAC,EAAE,oBAAoB,EAAE,KAAK,CAAC,oBAAoB,EAAE;YACtD,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,164 @@
1
+ import { createActionGate, jsonResult, readReactionParams, readStringParam, } from "openclaw/plugin-sdk";
2
+ import { resolveTlonAccount } from "./types.js";
3
+ import { normalizeShip, parseTlonTarget } from "./targets.js";
4
+ import { withAuthenticatedTlonApi } from "./urbit/api-client.js";
5
+ import { addChannelReaction, removeChannelReaction, addDmReaction, removeDmReaction, deleteHeapPost, sendChannelPost, } from "./urbit/send.js";
6
+ import { markdownToStory } from "./urbit/story.js";
7
+ const SUPPORTED_ACTIONS = new Set(["react", "delete", "reply"]);
8
+ export const tlonMessageActions = {
9
+ listActions: ({ cfg }) => {
10
+ const account = resolveTlonAccount(cfg);
11
+ if (!account.configured || !account.enabled) {
12
+ return [];
13
+ }
14
+ const gate = createActionGate(cfg.channels?.tlon?.actions);
15
+ const actions = [];
16
+ if (gate("reactions"))
17
+ actions.push("react");
18
+ if (gate("delete"))
19
+ actions.push("delete");
20
+ return actions;
21
+ },
22
+ supportsAction: ({ action }) => SUPPORTED_ACTIONS.has(action),
23
+ handleAction: async ({ action, params, cfg, accountId, toolContext }) => {
24
+ const account = resolveTlonAccount(cfg, accountId ?? undefined);
25
+ if (!account.configured || !account.ship || !account.url || !account.code) {
26
+ throw new Error("Tlon account not configured");
27
+ }
28
+ return await withAuthenticatedTlonApi({ url: account.url, code: account.code, ship: account.ship, allowPrivateNetwork: account.allowPrivateNetwork ?? undefined }, async () => {
29
+ const fromShip = normalizeShip(account.ship);
30
+ if (action === "react") {
31
+ const level = account.reactionLevel ?? "minimal";
32
+ if (level === "off" || level === "ack") {
33
+ throw new Error(`Tlon agent reactions disabled (reactionLevel="${level}"). ` +
34
+ `Set channels.tlon.reactionLevel to "minimal" or "extensive" to enable.`);
35
+ }
36
+ return await handleReact({ params, fromShip, toolContext });
37
+ }
38
+ if (action === "delete") {
39
+ return await handleDelete({ params, toolContext });
40
+ }
41
+ if (action === "reply") {
42
+ return await handleReply({ params, fromShip, toolContext });
43
+ }
44
+ throw new Error(`Tlon action "${action}" is not supported.`);
45
+ });
46
+ },
47
+ };
48
+ async function handleReact({ params, fromShip, toolContext, }) {
49
+ const { emoji, remove, isEmpty } = readReactionParams(params, {
50
+ removeErrorMessage: "Emoji is required to remove a Tlon reaction.",
51
+ });
52
+ if (isEmpty && !remove) {
53
+ throw new Error("Tlon react requires emoji parameter. Use action=react with emoji=<emoji> and messageId=<message_id>.");
54
+ }
55
+ const messageId = readStringParam(params, "messageId");
56
+ if (!messageId) {
57
+ throw new Error("Tlon react requires messageId parameter.");
58
+ }
59
+ const to = readStringParam(params, "target") ??
60
+ readStringParam(params, "to") ??
61
+ toolContext?.currentChannelId;
62
+ if (!to) {
63
+ throw new Error("Tlon react requires 'to' parameter (target channel or DM).");
64
+ }
65
+ const parsed = parseTlonTarget(to);
66
+ if (!parsed) {
67
+ throw new Error(`Invalid Tlon target: ${to}`);
68
+ }
69
+ // For reply/thread reactions: explicit parentId, or infer from thread context
70
+ const parentId = readStringParam(params, "parentId") ??
71
+ toolContext?.currentThreadTs ??
72
+ undefined;
73
+ if (parsed.kind === "dm") {
74
+ if (remove) {
75
+ await removeDmReaction({ fromShip, toShip: parsed.ship, messageId, parentId });
76
+ return jsonResult({ ok: true, removed: true });
77
+ }
78
+ await addDmReaction({ fromShip, toShip: parsed.ship, messageId, react: emoji, parentId });
79
+ return jsonResult({ ok: true, added: emoji });
80
+ }
81
+ // Channel reaction (chat, heap, or diary)
82
+ // Extract nest prefix from the nest string (e.g., "heap" from "heap/~host/channel")
83
+ const nestPrefix = parsed.nest.split("/")[0];
84
+ if (remove) {
85
+ await removeChannelReaction({
86
+ fromShip,
87
+ hostShip: parsed.hostShip,
88
+ channelName: parsed.channelName,
89
+ postId: messageId,
90
+ nestPrefix,
91
+ parentId,
92
+ });
93
+ return jsonResult({ ok: true, removed: true });
94
+ }
95
+ await addChannelReaction({
96
+ fromShip,
97
+ hostShip: parsed.hostShip,
98
+ channelName: parsed.channelName,
99
+ postId: messageId,
100
+ react: emoji,
101
+ nestPrefix,
102
+ parentId,
103
+ });
104
+ return jsonResult({ ok: true, added: emoji });
105
+ }
106
+ async function handleDelete({ params, toolContext, }) {
107
+ const messageId = readStringParam(params, "messageId");
108
+ if (!messageId) {
109
+ throw new Error("Tlon delete requires messageId parameter.");
110
+ }
111
+ const to = readStringParam(params, "target") ??
112
+ readStringParam(params, "to") ??
113
+ toolContext?.currentChannelId;
114
+ if (!to) {
115
+ throw new Error("Tlon delete requires 'to' parameter.");
116
+ }
117
+ const parsed = parseTlonTarget(to);
118
+ if (!parsed || parsed.kind === "dm") {
119
+ throw new Error("Tlon delete is only supported for channel posts.");
120
+ }
121
+ const nestPrefix = parsed.nest.split("/")[0];
122
+ if (nestPrefix !== "heap") {
123
+ throw new Error("Tlon delete is currently only supported for heap posts. Use heap/~host/channel as the target.");
124
+ }
125
+ await deleteHeapPost({
126
+ hostShip: parsed.hostShip,
127
+ channelName: parsed.channelName,
128
+ curioId: messageId,
129
+ });
130
+ return jsonResult({ ok: true, deleted: messageId });
131
+ }
132
+ async function handleReply({ params, fromShip, toolContext, }) {
133
+ const messageId = readStringParam(params, "messageId");
134
+ if (!messageId) {
135
+ throw new Error("Tlon reply requires messageId parameter (the ID of the post to reply to).");
136
+ }
137
+ const message = readStringParam(params, "message");
138
+ if (!message) {
139
+ throw new Error("Tlon reply requires message parameter (the reply text).");
140
+ }
141
+ const to = readStringParam(params, "target") ??
142
+ readStringParam(params, "to") ??
143
+ toolContext?.currentChannelId;
144
+ if (!to) {
145
+ throw new Error("Tlon reply requires 'to' parameter (target channel).");
146
+ }
147
+ const parsed = parseTlonTarget(to);
148
+ if (!parsed) {
149
+ throw new Error(`Invalid Tlon target: ${to}`);
150
+ }
151
+ const story = markdownToStory(message);
152
+ if (parsed.kind === "dm") {
153
+ throw new Error("Tlon reply action is supported for channel targets. For DMs, use action=send with replyTo.");
154
+ }
155
+ // Channel reply (chat, heap, or diary)
156
+ await sendChannelPost({
157
+ fromShip,
158
+ nest: parsed.nest,
159
+ story,
160
+ replyToId: messageId,
161
+ });
162
+ return jsonResult({ ok: true, replied: messageId, target: to });
163
+ }
164
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/actions.ts"],"names":[],"mappings":"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"}