clawmini 0.0.2 → 0.0.3

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 (102) hide show
  1. package/.github/workflows/ci.yml +59 -0
  2. package/README.md +4 -2
  3. package/dist/adapter-discord/index.d.mts.map +1 -1
  4. package/dist/adapter-discord/index.mjs +13 -4
  5. package/dist/adapter-discord/index.mjs.map +1 -1
  6. package/dist/cli/index.mjs +7 -6
  7. package/dist/cli/index.mjs.map +1 -1
  8. package/dist/cli/lite.mjs +16 -10
  9. package/dist/cli/lite.mjs.map +1 -1
  10. package/dist/daemon/index.mjs +590 -401
  11. package/dist/daemon/index.mjs.map +1 -1
  12. package/dist/{fetch-BjZVyU3Z.mjs → fetch-Cn1XNyiO.mjs} +1 -1
  13. package/dist/{fetch-BjZVyU3Z.mjs.map → fetch-Cn1XNyiO.mjs.map} +1 -1
  14. package/dist/lite-oSYSvaOr.mjs +164 -0
  15. package/dist/lite-oSYSvaOr.mjs.map +1 -0
  16. package/dist/web/_app/immutable/chunks/{CAZeqksE.js → 8YNcRyEk.js} +1 -1
  17. package/dist/web/_app/immutable/chunks/{B3YcEpQV.js → DQoygso7.js} +1 -1
  18. package/dist/web/_app/immutable/entry/{app.ZuicLpkH.js → app.DO5eYwVz.js} +2 -2
  19. package/dist/web/_app/immutable/entry/start.D48mVn1m.js +1 -0
  20. package/dist/web/_app/immutable/nodes/{0.BB1CjKco.js → 0.B-0CcADM.js} +1 -1
  21. package/dist/web/_app/immutable/nodes/{1.CdSgEHu9.js → 1.FixKgvRO.js} +1 -1
  22. package/{web/.svelte-kit/output/client/_app/immutable/nodes/3.CKp7Wkn8.js → dist/web/_app/immutable/nodes/3.ncP0xLO6.js} +1 -1
  23. package/dist/web/_app/immutable/nodes/{4.FyeoMY-Y.js → 4.CQYJEgv8.js} +1 -1
  24. package/dist/web/_app/immutable/nodes/{5.D6mVN7l7.js → 5.BpJUN6QH.js} +1 -1
  25. package/dist/web/_app/version.json +1 -1
  26. package/dist/web/index.html +6 -6
  27. package/dist/{workspace-BC1ahx4R.mjs → workspace-DjoNjhW0.mjs} +12 -42
  28. package/dist/workspace-DjoNjhW0.mjs.map +1 -0
  29. package/docs/15_lite_fetch_pending/development_log.md +31 -0
  30. package/docs/15_lite_fetch_pending/notes.md +48 -0
  31. package/docs/15_lite_fetch_pending/prd.md +39 -0
  32. package/docs/15_lite_fetch_pending/questions.md +3 -0
  33. package/docs/15_lite_fetch_pending/tickets.md +42 -0
  34. package/docs/CHECKS.md +2 -2
  35. package/eslint.config.js +12 -0
  36. package/package.json +3 -2
  37. package/src/adapter-discord/client.ts +1 -1
  38. package/src/adapter-discord/index.ts +22 -5
  39. package/src/cli/client.ts +8 -3
  40. package/src/cli/e2e/adapter-discord.test.ts +2 -2
  41. package/src/cli/e2e/daemon.test.ts +2 -1
  42. package/src/cli/e2e/export-lite-func.test.ts +41 -13
  43. package/src/cli/e2e/fallbacks.test.ts +4 -0
  44. package/src/cli/lite.ts +24 -6
  45. package/src/daemon/api/agent-router.ts +191 -0
  46. package/src/daemon/{router.test.ts → api/index.test.ts} +101 -34
  47. package/src/daemon/api/index.ts +4 -0
  48. package/src/daemon/{router-policy-request.test.ts → api/policy-request.test.ts} +27 -13
  49. package/src/daemon/api/router-utils.ts +159 -0
  50. package/src/daemon/api/trpc.ts +30 -0
  51. package/src/daemon/api/user-router.ts +221 -0
  52. package/src/daemon/index.ts +3 -3
  53. package/src/daemon/message-interruption.test.ts +17 -10
  54. package/src/daemon/message-typing.test.ts +1 -1
  55. package/src/daemon/message.ts +260 -239
  56. package/src/daemon/observation.test.ts +1 -1
  57. package/src/daemon/queue.test.ts +28 -0
  58. package/src/daemon/queue.ts +30 -15
  59. package/src/daemon/request-store.test.ts +4 -4
  60. package/src/daemon/request-store.ts +3 -1
  61. package/src/shared/workspace.ts +4 -5
  62. package/templates/debug/settings.json +5 -0
  63. package/templates/environments/macos/env.json +1 -1
  64. package/templates/environments/macos-proxy/env.json +1 -1
  65. package/templates/gemini-claw/.gemini/hooks/insert-pending.sh +9 -0
  66. package/templates/gemini-claw/.gemini/settings.json +14 -1
  67. package/templates/gemini-claw/.gemini/system.md +2 -0
  68. package/web/.svelte-kit/generated/server/internal.js +1 -1
  69. package/web/.svelte-kit/output/client/.vite/manifest.json +26 -26
  70. package/web/.svelte-kit/output/client/_app/immutable/chunks/{CAZeqksE.js → 8YNcRyEk.js} +1 -1
  71. package/web/.svelte-kit/output/client/_app/immutable/chunks/{B3YcEpQV.js → DQoygso7.js} +1 -1
  72. package/web/.svelte-kit/output/client/_app/immutable/entry/{app.ZuicLpkH.js → app.DO5eYwVz.js} +2 -2
  73. package/web/.svelte-kit/output/client/_app/immutable/entry/start.D48mVn1m.js +1 -0
  74. package/web/.svelte-kit/output/client/_app/immutable/nodes/{0.BB1CjKco.js → 0.B-0CcADM.js} +1 -1
  75. package/web/.svelte-kit/output/client/_app/immutable/nodes/{1.CdSgEHu9.js → 1.FixKgvRO.js} +1 -1
  76. package/{dist/web/_app/immutable/nodes/3.CKp7Wkn8.js → web/.svelte-kit/output/client/_app/immutable/nodes/3.ncP0xLO6.js} +1 -1
  77. package/web/.svelte-kit/output/client/_app/immutable/nodes/{4.FyeoMY-Y.js → 4.CQYJEgv8.js} +1 -1
  78. package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.D6mVN7l7.js → 5.BpJUN6QH.js} +1 -1
  79. package/web/.svelte-kit/output/client/_app/version.json +1 -1
  80. package/web/.svelte-kit/output/server/chunks/internal.js +1 -1
  81. package/web/.svelte-kit/output/server/manifest-full.js +1 -1
  82. package/web/.svelte-kit/output/server/manifest.js +1 -1
  83. package/web/.svelte-kit/output/server/nodes/0.js +1 -1
  84. package/web/.svelte-kit/output/server/nodes/1.js +1 -1
  85. package/web/.svelte-kit/output/server/nodes/3.js +1 -1
  86. package/web/.svelte-kit/output/server/nodes/4.js +1 -1
  87. package/web/.svelte-kit/output/server/nodes/5.js +1 -1
  88. package/dist/chats-BcbxvPlj.mjs +0 -29
  89. package/dist/chats-BcbxvPlj.mjs.map +0 -1
  90. package/dist/chats-CpRQrNHj.mjs +0 -91
  91. package/dist/chats-CpRQrNHj.mjs.map +0 -1
  92. package/dist/fs-B5wW0oaH.mjs +0 -14
  93. package/dist/fs-B5wW0oaH.mjs.map +0 -1
  94. package/dist/lite-DBUuHsX0.mjs +0 -80
  95. package/dist/lite-DBUuHsX0.mjs.map +0 -1
  96. package/dist/policy-utils-BvfOK6Ih.mjs +0 -114
  97. package/dist/policy-utils-BvfOK6Ih.mjs.map +0 -1
  98. package/dist/rolldown-runtime-95iHPtFO.mjs +0 -18
  99. package/dist/web/_app/immutable/entry/start.DuQwh4Nz.js +0 -1
  100. package/dist/workspace-BC1ahx4R.mjs.map +0 -1
  101. package/src/daemon/router.ts +0 -510
  102. package/web/.svelte-kit/output/client/_app/immutable/entry/start.DuQwh4Nz.js +0 -1
@@ -0,0 +1,59 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - master
8
+ pull_request:
9
+ branches:
10
+ - main
11
+ - master
12
+
13
+ jobs:
14
+ static-analysis:
15
+ name: Format, Lint & Check
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - name: Checkout repository
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Setup Node.js
22
+ uses: actions/setup-node@v4
23
+ with:
24
+ node-version: 22
25
+ cache: 'npm'
26
+
27
+ - name: Install dependencies
28
+ run: npm ci
29
+
30
+ - name: Run Prettier check
31
+ run: npm run format:check
32
+
33
+ - name: Run ESLint
34
+ run: npm run lint
35
+
36
+ - name: Run Type Check
37
+ run: npm run check
38
+
39
+ test:
40
+ name: Run Tests (Unit & E2E)
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - name: Checkout repository
44
+ uses: actions/checkout@v4
45
+
46
+ - name: Setup Node.js
47
+ uses: actions/setup-node@v4
48
+ with:
49
+ node-version: 22
50
+ cache: 'npm'
51
+
52
+ - name: Install dependencies
53
+ run: npm ci
54
+
55
+ - name: Install Playwright Browsers
56
+ run: npx playwright install --with-deps
57
+
58
+ - name: Run Tests
59
+ run: npm run test
package/README.md CHANGED
@@ -29,9 +29,9 @@ Let's set up a secure, sandboxed agent named Jeeves using the Gemini CLI templat
29
29
  npm install -g clawmini
30
30
 
31
31
  # 2. Initialize a workspace and create your first sandboxed agent
32
- # For a more OpenClaw-like experience, try the gemini-claw template
32
+ # Note: For a more basic experience, you can use the 'gemini' template instead
33
33
  mkdir my-workspace && cd my-workspace
34
- clawmini init --agent jeeves --agent-template gemini --environment macos
34
+ clawmini init --agent jeeves --agent-template gemini-claw --environment macos
35
35
 
36
36
  # 3. Start the background daemon
37
37
  clawmini up
@@ -42,6 +42,8 @@ clawmini web
42
42
 
43
43
  **Try asking Jeeves:** _"Summarize the recent changes in my git repository."_ Jeeves will run securely in its sandbox, read the diffs, and report back.
44
44
 
45
+ **What's going on?** When you send a message, Clawmini looks at the chat+message and then launches Gemini CLI with your message in the `jeeves/` directory. The `jeeves/` directory is set up with OpenClaw-like files and system prompt since you used the `gemini-claw` template. And since we chose the `macos` environment, Gemini CLI will run in a built-in Seatbelt sandbox that prevents it from editing anything outside your workspace folder. We additionally give Gemini CLI ways to schedule reminders and recurring tasks, send files, and request permissions to run sensitive commands (see Permission Requests).
46
+
45
47
  ### Common Slash Commands
46
48
 
47
49
  You can use these built-in slash commands in your chat interfaces:
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/adapter-discord/index.ts"],"mappings":";iBASsB,IAAA,CAAA,GAAI,OAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/adapter-discord/index.ts"],"mappings":";iBAUsB,IAAA,CAAA,GAAI,OAAA"}
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { l as getSocketPath, o as getClawminiDir, u as getWorkspaceRoot } from "../workspace-BC1ahx4R.mjs";
3
- import { t as createUnixSocketFetch } from "../fetch-BjZVyU3Z.mjs";
2
+ import { l as getSocketPath, o as getClawminiDir, u as getWorkspaceRoot } from "../workspace-DjoNjhW0.mjs";
3
+ import { t as createUnixSocketFetch } from "../fetch-Cn1XNyiO.mjs";
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import fs$1 from "node:fs/promises";
7
+ import { fileURLToPath } from "node:url";
7
8
  import { z } from "zod";
8
9
  import { createTRPCClient, httpLink, httpSubscriptionLink, splitLink } from "@trpc/client";
9
10
  import http from "node:http";
@@ -387,7 +388,6 @@ async function main() {
387
388
  console.log(`Received message from ${message.author.tag}: ${message.content}`);
388
389
  const downloadedFiles = [];
389
390
  if (message.attachments.size > 0) {
390
- const { getClawminiDir } = await import("../workspace-BC1ahx4R.mjs").then((n) => n.v);
391
391
  const tmpDir = path.join(getClawminiDir(process.cwd()), "tmp", "discord");
392
392
  await fs$1.mkdir(tmpDir, { recursive: true });
393
393
  const maxSizeMB = config.maxAttachmentSizeMB ?? 25;
@@ -446,7 +446,16 @@ async function main() {
446
446
  process.exit(1);
447
447
  }
448
448
  }
449
- main().catch((error) => {
449
+ if ((() => {
450
+ try {
451
+ if (typeof process === "undefined" || !process.argv || process.argv.length < 2) return false;
452
+ const argv1 = process.argv[1];
453
+ if (!argv1) return false;
454
+ return path.resolve(argv1) === path.resolve(fileURLToPath(import.meta.url));
455
+ } catch {
456
+ return false;
457
+ }
458
+ })()) main().catch((error) => {
450
459
  console.error("Unhandled error in Discord Adapter:", error);
451
460
  process.exit(1);
452
461
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["fsPromises","fsPromises","fs"],"sources":["../../src/adapter-discord/config.ts","../../src/shared/event-source.ts","../../src/adapter-discord/client.ts","../../src/adapter-discord/state.ts","../../src/adapter-discord/forwarder.ts","../../src/adapter-discord/index.ts"],"sourcesContent":["import fsPromises from 'node:fs/promises';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport { getClawminiDir } from '../shared/workspace.js';\nimport fs from 'node:fs';\n\nexport const DiscordConfigSchema = z.looseObject({\n botToken: z.string().min(1, 'Discord Bot Token is required.'),\n authorizedUserId: z.string().min(1, 'Authorized Discord User ID is required.'),\n chatId: z.string().default('default'),\n maxAttachmentSizeMB: z.number().default(25).optional(),\n});\n\nexport type DiscordConfig = z.infer<typeof DiscordConfigSchema>;\n\nexport function getDiscordConfigPath(startDir = process.cwd()): string {\n return path.join(getClawminiDir(startDir), 'adapters', 'discord', 'config.json');\n}\n\nexport async function readDiscordConfig(startDir = process.cwd()): Promise<DiscordConfig | null> {\n const configPath = getDiscordConfigPath(startDir);\n try {\n const data = await fsPromises.readFile(configPath, 'utf-8');\n const parsed = JSON.parse(data);\n const result = DiscordConfigSchema.safeParse(parsed);\n if (!result.success) {\n console.error('Invalid Discord configuration:', result.error.format());\n return null;\n }\n return result.data;\n } catch {\n // Return null if file doesn't exist or is invalid JSON\n return null;\n }\n}\n\nexport async function initDiscordConfig(startDir = process.cwd()): Promise<void> {\n const configPath = getDiscordConfigPath(startDir);\n const configDir = path.dirname(configPath);\n\n await fsPromises.mkdir(configDir, { recursive: true });\n\n if (fs.existsSync(configPath)) {\n console.log(`Config file already exists at ${configPath}`);\n return;\n }\n\n const templateConfig = {\n botToken: 'YOUR_DISCORD_BOT_TOKEN',\n authorizedUserId: 'YOUR_DISCORD_USER_ID',\n chatId: 'default',\n };\n\n await fsPromises.writeFile(configPath, JSON.stringify(templateConfig, null, 2), 'utf-8');\n console.log(`Created template configuration file at ${configPath}`);\n console.log('Please update it with your actual Discord Bot Token and User ID.');\n}\n\nexport function isAuthorized(userId: string, authorizedUserId: string): boolean {\n return userId === authorizedUserId;\n}\n","import http from 'node:http';\n\nexport function createUnixSocketEventSource(socketPath: string) {\n return class UnixSocketEventSource {\n public readyState: number = 0; // CONNECTING\n public readonly CONNECTING = 0;\n public readonly OPEN = 1;\n public readonly CLOSED = 2;\n\n req: http.ClientRequest | null = null;\n listeners: Record<string, ((event: Record<string, unknown>) => void)[]> = {};\n\n constructor(url: string, init?: Record<string, unknown>) {\n const parsedUrl = new URL(url);\n\n const options: http.RequestOptions = {\n socketPath,\n path: parsedUrl.pathname + parsedUrl.search,\n method: 'GET',\n headers: {\n Accept: 'text/event-stream',\n 'Cache-Control': 'no-cache',\n ...(init?.headers as Record<string, string> | undefined),\n },\n };\n\n this.req = http.request(options, (res) => {\n if (res.statusCode === 200) {\n this.readyState = this.OPEN;\n this.dispatchEvent({ type: 'open' });\n } else {\n this.readyState = this.CLOSED;\n this.dispatchEvent({\n type: 'error',\n message: `Unexpected status code: ${res.statusCode}`,\n });\n return;\n }\n\n let buffer = '';\n res.on('data', (chunk) => {\n buffer += chunk.toString('utf-8');\n const lines = buffer.split(/\\r?\\n\\r?\\n/);\n buffer = lines.pop() || '';\n\n for (const block of lines) {\n this.parseBlock(block);\n }\n });\n\n res.on('end', () => {\n if (buffer) this.parseBlock(buffer);\n this.readyState = this.CLOSED;\n this.dispatchEvent({ type: 'close' });\n });\n });\n\n this.req.on('error', (err) => {\n this.readyState = this.CLOSED;\n this.dispatchEvent({ type: 'error', error: err });\n });\n\n this.req.end();\n }\n\n parseBlock(block: string) {\n if (!block.trim()) return;\n\n const lines = block.split(/\\r?\\n/);\n let eventType = 'message';\n let data = '';\n let id = '';\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n eventType = line.slice(7).trim();\n } else if (line.startsWith('data: ')) {\n data += (data ? '\\n' : '') + line.slice(6);\n } else if (line.startsWith('id: ')) {\n id = line.slice(4).trim();\n }\n }\n\n if (data) {\n this.dispatchEvent({\n type: eventType,\n data,\n lastEventId: id,\n });\n }\n }\n\n public addEventListener(type: string, listener: (event: Record<string, unknown>) => void) {\n if (!this.listeners[type]) {\n this.listeners[type] = [];\n }\n this.listeners[type].push(listener);\n }\n\n public removeEventListener(type: string, listener: (event: Record<string, unknown>) => void) {\n if (!this.listeners[type]) return;\n this.listeners[type] = this.listeners[type].filter((l) => l !== listener);\n }\n\n dispatchEvent(event: Record<string, unknown>) {\n const type = event.type as string;\n if (this.listeners[type]) {\n for (const listener of this.listeners[type]) {\n listener(event);\n }\n }\n }\n\n public close() {\n this.readyState = this.CLOSED;\n if (this.req) {\n this.req.destroy();\n }\n }\n };\n}\n","import { createTRPCClient, httpLink, splitLink, httpSubscriptionLink } from '@trpc/client';\nimport type { AppRouter } from '../daemon/router.js';\nimport { getSocketPath } from '../shared/workspace.js';\nimport { createUnixSocketFetch } from '../shared/fetch.js';\nimport { createUnixSocketEventSource } from '../shared/event-source.js';\nimport fs from 'node:fs';\n\n/**\n * Creates a TRPC client that connects to the Clawmini daemon via a Unix socket.\n *\n * @param options - Configuration options for the client.\n * @returns A TRPC client instance for the AppRouter.\n */\nexport function getTRPCClient(options: { socketPath?: string } = {}) {\n const socketPath = options.socketPath ?? getSocketPath();\n\n if (!fs.existsSync(socketPath)) {\n throw new Error(`Daemon not running. Socket not found at ${socketPath}`);\n }\n\n const customFetch = createUnixSocketFetch(socketPath);\n const CustomEventSource = createUnixSocketEventSource(socketPath);\n\n return createTRPCClient<AppRouter>({\n links: [\n splitLink({\n condition(op) {\n return op.type === 'subscription';\n },\n true: httpSubscriptionLink({\n url: 'http://localhost',\n EventSource: CustomEventSource,\n }),\n false: httpLink({\n url: 'http://localhost',\n fetch: customFetch,\n }),\n }),\n ],\n });\n}\n","import fsPromises from 'node:fs/promises';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport { getClawminiDir } from '../shared/workspace.js';\n\nexport const DiscordStateSchema = z.object({\n lastSyncedMessageId: z.string().optional(),\n});\n\nexport type DiscordState = z.infer<typeof DiscordStateSchema>;\n\nexport function getDiscordStatePath(startDir = process.cwd()): string {\n return path.join(getClawminiDir(startDir), 'adapters', 'discord', 'state.json');\n}\n\nexport async function readDiscordState(startDir = process.cwd()): Promise<DiscordState> {\n const statePath = getDiscordStatePath(startDir);\n try {\n const data = await fsPromises.readFile(statePath, 'utf-8');\n const parsed = JSON.parse(data);\n const result = DiscordStateSchema.safeParse(parsed);\n if (!result.success) {\n return { lastSyncedMessageId: undefined };\n }\n return result.data;\n } catch {\n // Return default state if file doesn't exist or is invalid JSON\n return { lastSyncedMessageId: undefined };\n }\n}\n\nexport async function writeDiscordState(\n state: DiscordState,\n startDir = process.cwd()\n): Promise<void> {\n const statePath = getDiscordStatePath(startDir);\n const dir = path.dirname(statePath);\n try {\n await fsPromises.mkdir(dir, { recursive: true });\n await fsPromises.writeFile(statePath, JSON.stringify(state, null, 2), 'utf-8');\n } catch (err) {\n console.error(`Failed to write Discord state to ${statePath}:`, err);\n }\n}\n","import type { Client, MessageCreateOptions } from 'discord.js';\nimport path from 'node:path';\nimport type { getTRPCClient } from './client.js';\nimport { readDiscordState, writeDiscordState } from './state.js';\nimport type { ChatMessage, CommandLogMessage } from '../shared/chats.js';\nimport { getWorkspaceRoot } from '../shared/workspace.js';\n\nexport async function startDaemonToDiscordForwarder(\n client: Client,\n trpc: ReturnType<typeof getTRPCClient>,\n discordUserId: string,\n chatId: string = 'default',\n signal?: AbortSignal\n) {\n const state = await readDiscordState();\n let lastMessageId = state.lastSyncedMessageId;\n\n // 1. If we don't have a lastMessageId, get the most recent one from the daemon\n // to avoid sending the entire chat history on first run.\n if (!lastMessageId) {\n try {\n const messages = await trpc.getMessages.query({ chatId, limit: 1 });\n if (Array.isArray(messages) && messages.length > 0) {\n const lastMsg = messages[messages.length - 1];\n if (lastMsg) {\n lastMessageId = lastMsg.id;\n await writeDiscordState({ lastSyncedMessageId: lastMessageId });\n }\n }\n } catch (error) {\n if (signal?.aborted) return;\n console.error('Failed to fetch initial messages from daemon:', error);\n }\n }\n\n console.log(\n `Starting daemon-to-discord forwarder for chat ${chatId}, lastMessageId: ${lastMessageId}`\n );\n\n let retryDelay = 1000;\n const maxRetryDelay = 30000;\n\n // 2. Start the observation loop using tRPC subscription\n return new Promise<void>((resolve) => {\n let subscription: { unsubscribe: () => void } | null = null;\n let messageQueue = Promise.resolve();\n\n const connect = () => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n\n subscription = trpc.waitForMessages.subscribe(\n { chatId, lastMessageId },\n {\n onData: (messages) => {\n retryDelay = 1000; // Reset retry delay on successful data\n\n if (!Array.isArray(messages) || messages.length === 0) {\n return;\n }\n\n // Queue processing to ensure sequential execution\n messageQueue = messageQueue.then(async () => {\n for (const rawMessage of messages) {\n if (signal?.aborted) break;\n\n const message = rawMessage as ChatMessage;\n\n // Only forward logs (agent responses, system messages)\n if (message.role === 'log') {\n const logMessage = message as CommandLogMessage;\n\n if (logMessage.level === 'verbose') {\n lastMessageId = logMessage.id;\n await writeDiscordState({ lastSyncedMessageId: lastMessageId }).catch(\n console.error\n );\n continue;\n }\n\n const hasContent = !!logMessage.content?.trim();\n const hasFiles = Array.isArray(logMessage.files) && logMessage.files.length > 0;\n\n // The daemon stores logMessage.files as paths relative to the WORKSPACE directory\n // (the directory containing .clawmini). We must resolve these against the current\n // workspace root so discord.js can successfully locate and read the files.\n let absoluteFiles: string[] = [];\n if (hasFiles) {\n const workspaceRoot = getWorkspaceRoot(process.cwd());\n absoluteFiles = logMessage.files!.map((f) => path.resolve(workspaceRoot, f));\n }\n\n if (!hasContent && !hasFiles) {\n lastMessageId = logMessage.id;\n await writeDiscordState({ lastSyncedMessageId: lastMessageId }).catch(\n console.error\n );\n continue;\n }\n\n try {\n const user = await client.users.fetch(discordUserId);\n const dm = await user.createDM();\n\n // Discord has a 2000 character limit for messages.\n if (hasContent && logMessage.content.length > 2000) {\n const chunks = chunkString(logMessage.content, 2000);\n for (let i = 0; i < chunks.length; i++) {\n if (signal?.aborted) break;\n const chunkOptions: MessageCreateOptions = { content: chunks[i] as string };\n if (i === chunks.length - 1 && hasFiles) {\n chunkOptions.files = absoluteFiles;\n }\n await dm.send(chunkOptions);\n }\n } else {\n const options: MessageCreateOptions = {};\n if (hasContent) {\n options.content = logMessage.content;\n }\n if (hasFiles) {\n options.files = absoluteFiles;\n }\n await dm.send(options);\n }\n } catch (error) {\n console.error(\n `Failed to send message to Discord user ${discordUserId}:`,\n error\n );\n // We don't advance lastMessageId if sending failed\n break;\n }\n }\n\n lastMessageId = message.id;\n await writeDiscordState({ lastSyncedMessageId: lastMessageId }).catch(\n console.error\n );\n }\n });\n },\n onError: (error) => {\n console.error(\n `Error in daemon-to-discord forwarder subscription. Retrying in ${retryDelay}ms.`,\n error\n );\n subscription?.unsubscribe();\n subscription = null;\n\n if (signal?.aborted) {\n resolve();\n return;\n }\n\n setTimeout(() => {\n retryDelay = Math.min(retryDelay * 2, maxRetryDelay);\n connect();\n }, retryDelay);\n },\n onComplete: () => {\n subscription = null;\n if (!signal?.aborted) {\n setTimeout(() => connect(), retryDelay);\n } else {\n resolve();\n }\n },\n }\n );\n };\n\n let typingSubscription: { unsubscribe: () => void } | null = null;\n let typingRetryDelay = 1000;\n\n const connectTyping = () => {\n if (signal?.aborted) {\n return;\n }\n\n typingSubscription = trpc.waitForTyping.subscribe(\n { chatId },\n {\n onData: async (event) => {\n typingRetryDelay = 1000; // Reset retry delay on successful data\n if (!event) return;\n\n try {\n const user = await client.users.fetch(discordUserId);\n const dm = await user.createDM();\n await dm.sendTyping();\n } catch (error) {\n console.error(\n `Failed to send typing indicator to Discord user ${discordUserId}:`,\n error\n );\n }\n },\n onError: (error) => {\n console.error(\n `Error in daemon-to-discord typing forwarder subscription. Retrying in ${typingRetryDelay}ms.`,\n error\n );\n typingSubscription?.unsubscribe();\n typingSubscription = null;\n\n if (signal?.aborted) {\n return;\n }\n\n setTimeout(() => {\n typingRetryDelay = Math.min(typingRetryDelay * 2, maxRetryDelay);\n connectTyping();\n }, typingRetryDelay);\n },\n onComplete: () => {\n typingSubscription = null;\n if (!signal?.aborted) {\n setTimeout(() => connectTyping(), typingRetryDelay);\n }\n },\n }\n );\n };\n\n connect();\n connectTyping();\n\n signal?.addEventListener('abort', () => {\n subscription?.unsubscribe();\n typingSubscription?.unsubscribe();\n resolve();\n });\n });\n}\n\nfunction chunkString(str: string, size: number): string[] {\n const chunks: string[] = [];\n const chars = Array.from(str);\n for (let i = 0; i < chars.length; i += size) {\n chunks.push(chars.slice(i, i + size).join(''));\n }\n return chunks;\n}\n","#!/usr/bin/env node\n\nimport { Client, Events, GatewayIntentBits, Partials } from 'discord.js';\nimport { readDiscordConfig, isAuthorized, initDiscordConfig } from './config.js';\nimport { getTRPCClient } from './client.js';\nimport { startDaemonToDiscordForwarder } from './forwarder.js';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport async function main() {\n const args = process.argv.slice(2);\n\n if (args[0] === 'init') {\n await initDiscordConfig();\n return;\n }\n\n console.log('Discord Adapter starting...');\n\n const config = await readDiscordConfig();\n if (!config) {\n console.error(\n 'Failed to load Discord configuration. Please ensure .clawmini/adapters/discord/config.json exists and is valid.'\n );\n process.exit(1);\n }\n\n const trpc = getTRPCClient();\n\n const client = new Client({\n intents: [GatewayIntentBits.DirectMessages, GatewayIntentBits.MessageContent],\n partials: [Partials.Channel],\n });\n\n client.once(Events.ClientReady, (readyClient) => {\n console.log(`Ready! Logged in as ${readyClient.user.tag}`);\n\n // Start forwarding from daemon to Discord\n startDaemonToDiscordForwarder(readyClient, trpc, config.authorizedUserId, config.chatId).catch(\n (error) => {\n console.error('Error in daemon-to-discord forwarder:', error);\n }\n );\n });\n\n client.on(Events.MessageCreate, async (message) => {\n // Ignore messages from the bot itself\n if (message.author.id === client.user?.id) return;\n\n // Only handle DM messages\n if (message.guild) return;\n\n // Check if the user is authorized\n if (!isAuthorized(message.author.id, config.authorizedUserId)) {\n console.log(\n `Unauthorized message from ${message.author.tag} (${message.author.id}) ignored.`\n );\n return;\n }\n\n console.log(`Received message from ${message.author.tag}: ${message.content}`);\n\n const downloadedFiles: string[] = [];\n if (message.attachments.size > 0) {\n const { getClawminiDir } = await import('../shared/workspace.js');\n const tmpDir = path.join(getClawminiDir(process.cwd()), 'tmp', 'discord');\n await fs.mkdir(tmpDir, { recursive: true });\n const maxSizeMB = config.maxAttachmentSizeMB ?? 25;\n const maxSizeBytes = maxSizeMB * 1024 * 1024;\n\n for (const attachment of message.attachments.values()) {\n if (attachment.size > maxSizeBytes) {\n console.warn(\n `Attachment ${attachment.name} exceeds size limit (${maxSizeMB}MB). Ignoring.`\n );\n await message.reply(\n `Warning: Attachment ${attachment.name} exceeds the size limit of ${maxSizeMB}MB and was ignored.`\n );\n continue;\n }\n\n try {\n const res = await fetch(attachment.url);\n if (!res.ok) {\n console.error(`Failed to download attachment ${attachment.name}`);\n continue;\n }\n\n const uniqueName = `${Date.now()}-${attachment.name}`;\n const filePath = path.join(tmpDir, uniqueName);\n const arrayBuffer = await res.arrayBuffer();\n await fs.writeFile(filePath, Buffer.from(arrayBuffer));\n downloadedFiles.push(filePath);\n } catch (err) {\n console.error(`Error downloading attachment ${attachment.name}:`, err);\n }\n }\n }\n\n let finalContent = message.content;\n\n if (message.reference && message.reference.messageId) {\n try {\n const referencedMessage = await message.fetchReference();\n if (referencedMessage && referencedMessage.content) {\n const quotedContent = referencedMessage.content\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n');\n finalContent = `${quotedContent}\\n${finalContent}`;\n }\n } catch (err) {\n console.error('Failed to fetch referenced message:', err);\n }\n }\n\n console.log(`Forwarding message to daemon: ${finalContent}`);\n try {\n await trpc.sendMessage.mutate({\n type: 'send-message',\n client: 'cli',\n data: {\n message: finalContent,\n chatId: config.chatId,\n files: downloadedFiles.length > 0 ? downloadedFiles : undefined,\n adapter: 'discord',\n noWait: true,\n },\n });\n console.log('Message forwarded to daemon successfully.');\n } catch (error) {\n console.error('Failed to forward message to daemon:', error);\n }\n });\n\n try {\n await client.login(config.botToken);\n } catch (error) {\n console.error('Failed to login to Discord:', error);\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error('Unhandled error in Discord Adapter:', error);\n process.exit(1);\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["fsPromises","fsPromises","fs"],"sources":["../../src/adapter-discord/config.ts","../../src/shared/event-source.ts","../../src/adapter-discord/client.ts","../../src/adapter-discord/state.ts","../../src/adapter-discord/forwarder.ts","../../src/adapter-discord/index.ts"],"sourcesContent":["import fsPromises from 'node:fs/promises';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport { getClawminiDir } from '../shared/workspace.js';\nimport fs from 'node:fs';\n\nexport const DiscordConfigSchema = z.looseObject({\n botToken: z.string().min(1, 'Discord Bot Token is required.'),\n authorizedUserId: z.string().min(1, 'Authorized Discord User ID is required.'),\n chatId: z.string().default('default'),\n maxAttachmentSizeMB: z.number().default(25).optional(),\n});\n\nexport type DiscordConfig = z.infer<typeof DiscordConfigSchema>;\n\nexport function getDiscordConfigPath(startDir = process.cwd()): string {\n return path.join(getClawminiDir(startDir), 'adapters', 'discord', 'config.json');\n}\n\nexport async function readDiscordConfig(startDir = process.cwd()): Promise<DiscordConfig | null> {\n const configPath = getDiscordConfigPath(startDir);\n try {\n const data = await fsPromises.readFile(configPath, 'utf-8');\n const parsed = JSON.parse(data);\n const result = DiscordConfigSchema.safeParse(parsed);\n if (!result.success) {\n console.error('Invalid Discord configuration:', result.error.format());\n return null;\n }\n return result.data;\n } catch {\n // Return null if file doesn't exist or is invalid JSON\n return null;\n }\n}\n\nexport async function initDiscordConfig(startDir = process.cwd()): Promise<void> {\n const configPath = getDiscordConfigPath(startDir);\n const configDir = path.dirname(configPath);\n\n await fsPromises.mkdir(configDir, { recursive: true });\n\n if (fs.existsSync(configPath)) {\n console.log(`Config file already exists at ${configPath}`);\n return;\n }\n\n const templateConfig = {\n botToken: 'YOUR_DISCORD_BOT_TOKEN',\n authorizedUserId: 'YOUR_DISCORD_USER_ID',\n chatId: 'default',\n };\n\n await fsPromises.writeFile(configPath, JSON.stringify(templateConfig, null, 2), 'utf-8');\n console.log(`Created template configuration file at ${configPath}`);\n console.log('Please update it with your actual Discord Bot Token and User ID.');\n}\n\nexport function isAuthorized(userId: string, authorizedUserId: string): boolean {\n return userId === authorizedUserId;\n}\n","import http from 'node:http';\n\nexport function createUnixSocketEventSource(socketPath: string) {\n return class UnixSocketEventSource {\n public readyState: number = 0; // CONNECTING\n public readonly CONNECTING = 0;\n public readonly OPEN = 1;\n public readonly CLOSED = 2;\n\n req: http.ClientRequest | null = null;\n listeners: Record<string, ((event: Record<string, unknown>) => void)[]> = {};\n\n constructor(url: string, init?: Record<string, unknown>) {\n const parsedUrl = new URL(url);\n\n const options: http.RequestOptions = {\n socketPath,\n path: parsedUrl.pathname + parsedUrl.search,\n method: 'GET',\n headers: {\n Accept: 'text/event-stream',\n 'Cache-Control': 'no-cache',\n ...(init?.headers as Record<string, string> | undefined),\n },\n };\n\n this.req = http.request(options, (res) => {\n if (res.statusCode === 200) {\n this.readyState = this.OPEN;\n this.dispatchEvent({ type: 'open' });\n } else {\n this.readyState = this.CLOSED;\n this.dispatchEvent({\n type: 'error',\n message: `Unexpected status code: ${res.statusCode}`,\n });\n return;\n }\n\n let buffer = '';\n res.on('data', (chunk) => {\n buffer += chunk.toString('utf-8');\n const lines = buffer.split(/\\r?\\n\\r?\\n/);\n buffer = lines.pop() || '';\n\n for (const block of lines) {\n this.parseBlock(block);\n }\n });\n\n res.on('end', () => {\n if (buffer) this.parseBlock(buffer);\n this.readyState = this.CLOSED;\n this.dispatchEvent({ type: 'close' });\n });\n });\n\n this.req.on('error', (err) => {\n this.readyState = this.CLOSED;\n this.dispatchEvent({ type: 'error', error: err });\n });\n\n this.req.end();\n }\n\n parseBlock(block: string) {\n if (!block.trim()) return;\n\n const lines = block.split(/\\r?\\n/);\n let eventType = 'message';\n let data = '';\n let id = '';\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n eventType = line.slice(7).trim();\n } else if (line.startsWith('data: ')) {\n data += (data ? '\\n' : '') + line.slice(6);\n } else if (line.startsWith('id: ')) {\n id = line.slice(4).trim();\n }\n }\n\n if (data) {\n this.dispatchEvent({\n type: eventType,\n data,\n lastEventId: id,\n });\n }\n }\n\n public addEventListener(type: string, listener: (event: Record<string, unknown>) => void) {\n if (!this.listeners[type]) {\n this.listeners[type] = [];\n }\n this.listeners[type].push(listener);\n }\n\n public removeEventListener(type: string, listener: (event: Record<string, unknown>) => void) {\n if (!this.listeners[type]) return;\n this.listeners[type] = this.listeners[type].filter((l) => l !== listener);\n }\n\n dispatchEvent(event: Record<string, unknown>) {\n const type = event.type as string;\n if (this.listeners[type]) {\n for (const listener of this.listeners[type]) {\n listener(event);\n }\n }\n }\n\n public close() {\n this.readyState = this.CLOSED;\n if (this.req) {\n this.req.destroy();\n }\n }\n };\n}\n","import { createTRPCClient, httpLink, splitLink, httpSubscriptionLink } from '@trpc/client';\nimport type { UserRouter as AppRouter } from '../daemon/api/index.js';\nimport { getSocketPath } from '../shared/workspace.js';\nimport { createUnixSocketFetch } from '../shared/fetch.js';\nimport { createUnixSocketEventSource } from '../shared/event-source.js';\nimport fs from 'node:fs';\n\n/**\n * Creates a TRPC client that connects to the Clawmini daemon via a Unix socket.\n *\n * @param options - Configuration options for the client.\n * @returns A TRPC client instance for the AppRouter.\n */\nexport function getTRPCClient(options: { socketPath?: string } = {}) {\n const socketPath = options.socketPath ?? getSocketPath();\n\n if (!fs.existsSync(socketPath)) {\n throw new Error(`Daemon not running. Socket not found at ${socketPath}`);\n }\n\n const customFetch = createUnixSocketFetch(socketPath);\n const CustomEventSource = createUnixSocketEventSource(socketPath);\n\n return createTRPCClient<AppRouter>({\n links: [\n splitLink({\n condition(op) {\n return op.type === 'subscription';\n },\n true: httpSubscriptionLink({\n url: 'http://localhost',\n EventSource: CustomEventSource,\n }),\n false: httpLink({\n url: 'http://localhost',\n fetch: customFetch,\n }),\n }),\n ],\n });\n}\n","import fsPromises from 'node:fs/promises';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport { getClawminiDir } from '../shared/workspace.js';\n\nexport const DiscordStateSchema = z.object({\n lastSyncedMessageId: z.string().optional(),\n});\n\nexport type DiscordState = z.infer<typeof DiscordStateSchema>;\n\nexport function getDiscordStatePath(startDir = process.cwd()): string {\n return path.join(getClawminiDir(startDir), 'adapters', 'discord', 'state.json');\n}\n\nexport async function readDiscordState(startDir = process.cwd()): Promise<DiscordState> {\n const statePath = getDiscordStatePath(startDir);\n try {\n const data = await fsPromises.readFile(statePath, 'utf-8');\n const parsed = JSON.parse(data);\n const result = DiscordStateSchema.safeParse(parsed);\n if (!result.success) {\n return { lastSyncedMessageId: undefined };\n }\n return result.data;\n } catch {\n // Return default state if file doesn't exist or is invalid JSON\n return { lastSyncedMessageId: undefined };\n }\n}\n\nexport async function writeDiscordState(\n state: DiscordState,\n startDir = process.cwd()\n): Promise<void> {\n const statePath = getDiscordStatePath(startDir);\n const dir = path.dirname(statePath);\n try {\n await fsPromises.mkdir(dir, { recursive: true });\n await fsPromises.writeFile(statePath, JSON.stringify(state, null, 2), 'utf-8');\n } catch (err) {\n console.error(`Failed to write Discord state to ${statePath}:`, err);\n }\n}\n","import type { Client, MessageCreateOptions } from 'discord.js';\nimport path from 'node:path';\nimport type { getTRPCClient } from './client.js';\nimport { readDiscordState, writeDiscordState } from './state.js';\nimport type { ChatMessage, CommandLogMessage } from '../shared/chats.js';\nimport { getWorkspaceRoot } from '../shared/workspace.js';\n\nexport async function startDaemonToDiscordForwarder(\n client: Client,\n trpc: ReturnType<typeof getTRPCClient>,\n discordUserId: string,\n chatId: string = 'default',\n signal?: AbortSignal\n) {\n const state = await readDiscordState();\n let lastMessageId = state.lastSyncedMessageId;\n\n // 1. If we don't have a lastMessageId, get the most recent one from the daemon\n // to avoid sending the entire chat history on first run.\n if (!lastMessageId) {\n try {\n const messages = await trpc.getMessages.query({ chatId, limit: 1 });\n if (Array.isArray(messages) && messages.length > 0) {\n const lastMsg = messages[messages.length - 1];\n if (lastMsg) {\n lastMessageId = lastMsg.id;\n await writeDiscordState({ lastSyncedMessageId: lastMessageId });\n }\n }\n } catch (error) {\n if (signal?.aborted) return;\n console.error('Failed to fetch initial messages from daemon:', error);\n }\n }\n\n console.log(\n `Starting daemon-to-discord forwarder for chat ${chatId}, lastMessageId: ${lastMessageId}`\n );\n\n let retryDelay = 1000;\n const maxRetryDelay = 30000;\n\n // 2. Start the observation loop using tRPC subscription\n return new Promise<void>((resolve) => {\n let subscription: { unsubscribe: () => void } | null = null;\n let messageQueue = Promise.resolve();\n\n const connect = () => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n\n subscription = trpc.waitForMessages.subscribe(\n { chatId, lastMessageId },\n {\n onData: (messages) => {\n retryDelay = 1000; // Reset retry delay on successful data\n\n if (!Array.isArray(messages) || messages.length === 0) {\n return;\n }\n\n // Queue processing to ensure sequential execution\n messageQueue = messageQueue.then(async () => {\n for (const rawMessage of messages) {\n if (signal?.aborted) break;\n\n const message = rawMessage as ChatMessage;\n\n // Only forward logs (agent responses, system messages)\n if (message.role === 'log') {\n const logMessage = message as CommandLogMessage;\n\n if (logMessage.level === 'verbose') {\n lastMessageId = logMessage.id;\n await writeDiscordState({ lastSyncedMessageId: lastMessageId }).catch(\n console.error\n );\n continue;\n }\n\n const hasContent = !!logMessage.content?.trim();\n const hasFiles = Array.isArray(logMessage.files) && logMessage.files.length > 0;\n\n // The daemon stores logMessage.files as paths relative to the WORKSPACE directory\n // (the directory containing .clawmini). We must resolve these against the current\n // workspace root so discord.js can successfully locate and read the files.\n let absoluteFiles: string[] = [];\n if (hasFiles) {\n const workspaceRoot = getWorkspaceRoot(process.cwd());\n absoluteFiles = logMessage.files!.map((f) => path.resolve(workspaceRoot, f));\n }\n\n if (!hasContent && !hasFiles) {\n lastMessageId = logMessage.id;\n await writeDiscordState({ lastSyncedMessageId: lastMessageId }).catch(\n console.error\n );\n continue;\n }\n\n try {\n const user = await client.users.fetch(discordUserId);\n const dm = await user.createDM();\n\n // Discord has a 2000 character limit for messages.\n if (hasContent && logMessage.content.length > 2000) {\n const chunks = chunkString(logMessage.content, 2000);\n for (let i = 0; i < chunks.length; i++) {\n if (signal?.aborted) break;\n const chunkOptions: MessageCreateOptions = { content: chunks[i] as string };\n if (i === chunks.length - 1 && hasFiles) {\n chunkOptions.files = absoluteFiles;\n }\n await dm.send(chunkOptions);\n }\n } else {\n const options: MessageCreateOptions = {};\n if (hasContent) {\n options.content = logMessage.content;\n }\n if (hasFiles) {\n options.files = absoluteFiles;\n }\n await dm.send(options);\n }\n } catch (error) {\n console.error(\n `Failed to send message to Discord user ${discordUserId}:`,\n error\n );\n // We don't advance lastMessageId if sending failed\n break;\n }\n }\n\n lastMessageId = message.id;\n await writeDiscordState({ lastSyncedMessageId: lastMessageId }).catch(\n console.error\n );\n }\n });\n },\n onError: (error) => {\n console.error(\n `Error in daemon-to-discord forwarder subscription. Retrying in ${retryDelay}ms.`,\n error\n );\n subscription?.unsubscribe();\n subscription = null;\n\n if (signal?.aborted) {\n resolve();\n return;\n }\n\n setTimeout(() => {\n retryDelay = Math.min(retryDelay * 2, maxRetryDelay);\n connect();\n }, retryDelay);\n },\n onComplete: () => {\n subscription = null;\n if (!signal?.aborted) {\n setTimeout(() => connect(), retryDelay);\n } else {\n resolve();\n }\n },\n }\n );\n };\n\n let typingSubscription: { unsubscribe: () => void } | null = null;\n let typingRetryDelay = 1000;\n\n const connectTyping = () => {\n if (signal?.aborted) {\n return;\n }\n\n typingSubscription = trpc.waitForTyping.subscribe(\n { chatId },\n {\n onData: async (event) => {\n typingRetryDelay = 1000; // Reset retry delay on successful data\n if (!event) return;\n\n try {\n const user = await client.users.fetch(discordUserId);\n const dm = await user.createDM();\n await dm.sendTyping();\n } catch (error) {\n console.error(\n `Failed to send typing indicator to Discord user ${discordUserId}:`,\n error\n );\n }\n },\n onError: (error) => {\n console.error(\n `Error in daemon-to-discord typing forwarder subscription. Retrying in ${typingRetryDelay}ms.`,\n error\n );\n typingSubscription?.unsubscribe();\n typingSubscription = null;\n\n if (signal?.aborted) {\n return;\n }\n\n setTimeout(() => {\n typingRetryDelay = Math.min(typingRetryDelay * 2, maxRetryDelay);\n connectTyping();\n }, typingRetryDelay);\n },\n onComplete: () => {\n typingSubscription = null;\n if (!signal?.aborted) {\n setTimeout(() => connectTyping(), typingRetryDelay);\n }\n },\n }\n );\n };\n\n connect();\n connectTyping();\n\n signal?.addEventListener('abort', () => {\n subscription?.unsubscribe();\n typingSubscription?.unsubscribe();\n resolve();\n });\n });\n}\n\nfunction chunkString(str: string, size: number): string[] {\n const chunks: string[] = [];\n const chars = Array.from(str);\n for (let i = 0; i < chars.length; i += size) {\n chunks.push(chars.slice(i, i + size).join(''));\n }\n return chunks;\n}\n","#!/usr/bin/env node\n\nimport { Client, Events, GatewayIntentBits, Partials } from 'discord.js';\nimport { readDiscordConfig, isAuthorized, initDiscordConfig } from './config.js';\nimport { getTRPCClient } from './client.js';\nimport { startDaemonToDiscordForwarder } from './forwarder.js';\nimport { getClawminiDir } from '../shared/workspace.js';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport async function main() {\n const args = process.argv.slice(2);\n\n if (args[0] === 'init') {\n await initDiscordConfig();\n return;\n }\n\n console.log('Discord Adapter starting...');\n\n const config = await readDiscordConfig();\n if (!config) {\n console.error(\n 'Failed to load Discord configuration. Please ensure .clawmini/adapters/discord/config.json exists and is valid.'\n );\n process.exit(1);\n }\n\n const trpc = getTRPCClient();\n\n const client = new Client({\n intents: [GatewayIntentBits.DirectMessages, GatewayIntentBits.MessageContent],\n partials: [Partials.Channel],\n });\n\n client.once(Events.ClientReady, (readyClient) => {\n console.log(`Ready! Logged in as ${readyClient.user.tag}`);\n\n // Start forwarding from daemon to Discord\n startDaemonToDiscordForwarder(readyClient, trpc, config.authorizedUserId, config.chatId).catch(\n (error) => {\n console.error('Error in daemon-to-discord forwarder:', error);\n }\n );\n });\n\n client.on(Events.MessageCreate, async (message) => {\n // Ignore messages from the bot itself\n if (message.author.id === client.user?.id) return;\n\n // Only handle DM messages\n if (message.guild) return;\n\n // Check if the user is authorized\n if (!isAuthorized(message.author.id, config.authorizedUserId)) {\n console.log(\n `Unauthorized message from ${message.author.tag} (${message.author.id}) ignored.`\n );\n return;\n }\n\n console.log(`Received message from ${message.author.tag}: ${message.content}`);\n\n const downloadedFiles: string[] = [];\n if (message.attachments.size > 0) {\n const tmpDir = path.join(getClawminiDir(process.cwd()), 'tmp', 'discord');\n await fs.mkdir(tmpDir, { recursive: true });\n const maxSizeMB = config.maxAttachmentSizeMB ?? 25;\n const maxSizeBytes = maxSizeMB * 1024 * 1024;\n\n for (const attachment of message.attachments.values()) {\n if (attachment.size > maxSizeBytes) {\n console.warn(\n `Attachment ${attachment.name} exceeds size limit (${maxSizeMB}MB). Ignoring.`\n );\n await message.reply(\n `Warning: Attachment ${attachment.name} exceeds the size limit of ${maxSizeMB}MB and was ignored.`\n );\n continue;\n }\n\n try {\n const res = await fetch(attachment.url);\n if (!res.ok) {\n console.error(`Failed to download attachment ${attachment.name}`);\n continue;\n }\n\n const uniqueName = `${Date.now()}-${attachment.name}`;\n const filePath = path.join(tmpDir, uniqueName);\n const arrayBuffer = await res.arrayBuffer();\n await fs.writeFile(filePath, Buffer.from(arrayBuffer));\n downloadedFiles.push(filePath);\n } catch (err) {\n console.error(`Error downloading attachment ${attachment.name}:`, err);\n }\n }\n }\n\n let finalContent = message.content;\n\n if (message.reference && message.reference.messageId) {\n try {\n const referencedMessage = await message.fetchReference();\n if (referencedMessage && referencedMessage.content) {\n const quotedContent = referencedMessage.content\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n');\n finalContent = `${quotedContent}\\n${finalContent}`;\n }\n } catch (err) {\n console.error('Failed to fetch referenced message:', err);\n }\n }\n\n console.log(`Forwarding message to daemon: ${finalContent}`);\n try {\n await trpc.sendMessage.mutate({\n type: 'send-message',\n client: 'cli',\n data: {\n message: finalContent,\n chatId: config.chatId,\n files: downloadedFiles.length > 0 ? downloadedFiles : undefined,\n adapter: 'discord',\n noWait: true,\n },\n });\n console.log('Message forwarded to daemon successfully.');\n } catch (error) {\n console.error('Failed to forward message to daemon:', error);\n }\n });\n\n try {\n await client.login(config.botToken);\n } catch (error) {\n console.error('Failed to login to Discord:', error);\n process.exit(1);\n }\n}\n\nimport { fileURLToPath } from 'node:url';\n\nconst isMainModule = (() => {\n try {\n if (typeof process === 'undefined' || !process.argv || process.argv.length < 2) return false;\n const argv1 = process.argv[1];\n if (!argv1) return false;\n const p1 = path.resolve(argv1);\n const p2 = path.resolve(fileURLToPath(import.meta.url));\n return p1 === p2;\n } catch {\n return false;\n }\n})();\n\nif (isMainModule) {\n main().catch((error) => {\n console.error('Unhandled error in Discord Adapter:', error);\n process.exit(1);\n });\n}\n"],"mappings":"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"}
@@ -1,9 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { S as writeSettings, _ as readSettings, a as getAgent, b as writeAgentSettings, d as isValidAgentId, f as listAgents, l as getSocketPath, m as readChatSettings, n as deleteAgent, o as getClawminiDir, r as enableEnvironment, t as applyTemplateToAgent, x as writeChatSettings } from "../workspace-BC1ahx4R.mjs";
3
- import { n as pathIsInsideDir } from "../fs-B5wW0oaH.mjs";
4
- import { a as getChatsDir, c as isValidChatId, i as deleteChat, l as listChats, o as getDefaultChatId, r as createChat, s as getMessages, t as DEFAULT_CHAT_ID, u as setDefaultChatId } from "../chats-CpRQrNHj.mjs";
5
- import { t as createUnixSocketFetch } from "../fetch-BjZVyU3Z.mjs";
6
- import { i as writeLiteScript, r as getLiteScriptContent, t as exportLiteToAllEnvironments } from "../lite-DBUuHsX0.mjs";
2
+ import { S as pathIsInsideDir, _ as readSettings, a as getAgent, b as writeChatSettings, d as isValidAgentId, f as listAgents, l as getSocketPath, m as readChatSettings, n as deleteAgent, o as getClawminiDir, r as enableEnvironment, t as applyTemplateToAgent, x as writeSettings, y as writeAgentSettings } from "../workspace-DjoNjhW0.mjs";
3
+ import { a as DEFAULT_CHAT_ID, c as deleteChat, d as getMessages, f as isValidChatId, i as writeLiteScript, l as getChatsDir, m as setDefaultChatId, p as listChats, r as getLiteScriptContent, s as createChat, t as exportLiteToAllEnvironments, u as getDefaultChatId } from "../lite-oSYSvaOr.mjs";
4
+ import { t as createUnixSocketFetch } from "../fetch-Cn1XNyiO.mjs";
7
5
  import { Command } from "commander";
8
6
  import fs from "node:fs";
9
7
  import path from "node:path";
@@ -98,7 +96,10 @@ async function getDaemonClient(options = {}) {
98
96
  logFile
99
97
  ]
100
98
  }).unref();
101
- await new Promise((resolve) => setTimeout(resolve, 500));
99
+ for (let i = 0; i < 50; i++) {
100
+ await new Promise((resolve) => setTimeout(resolve, 100));
101
+ if (fs.existsSync(socketPath)) break;
102
+ }
102
103
  if (!fs.existsSync(socketPath)) throw new Error("Failed to start daemon.");
103
104
  }
104
105
  return createTRPCClient({ links: [httpLink({