pikiloop 0.4.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 (154) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +353 -0
  3. package/README.v2.md +287 -0
  4. package/README.zh-CN.md +352 -0
  5. package/dashboard/dist/assets/AgentTab-UZPIhlkr.js +1 -0
  6. package/dashboard/dist/assets/DirBrowser-Ckcmi-Pi.js +1 -0
  7. package/dashboard/dist/assets/ExtensionsTab-KZhEDrdu.js +1 -0
  8. package/dashboard/dist/assets/IMAccessTab-Bd_IY1GQ.js +1 -0
  9. package/dashboard/dist/assets/Modal-CTeL0y7P.js +1 -0
  10. package/dashboard/dist/assets/Modals-axftHasy.js +1 -0
  11. package/dashboard/dist/assets/Select-C8tOdPhe.js +1 -0
  12. package/dashboard/dist/assets/SessionPanel-C1geSRxw.js +1 -0
  13. package/dashboard/dist/assets/SystemTab-DBDkaPiO.js +1 -0
  14. package/dashboard/dist/assets/anthropic-BAdojD7P.ico +0 -0
  15. package/dashboard/dist/assets/codex-DYadqqp0.png +0 -0
  16. package/dashboard/dist/assets/deepseek-BeYNZEk0.ico +0 -0
  17. package/dashboard/dist/assets/doubao-DloFDuFR.png +0 -0
  18. package/dashboard/dist/assets/feishu-C4OMrjCW.ico +0 -0
  19. package/dashboard/dist/assets/gemini-BYkEpiWr.svg +1 -0
  20. package/dashboard/dist/assets/hermes-BAarh-tH.png +0 -0
  21. package/dashboard/dist/assets/index-CpM4CqZJ.js +23 -0
  22. package/dashboard/dist/assets/index-DXSohzrE.js +3 -0
  23. package/dashboard/dist/assets/index-reSbuley.css +1 -0
  24. package/dashboard/dist/assets/markdown-DxQYQFeH.js +29 -0
  25. package/dashboard/dist/assets/minimax-PuEGTfrF.ico +0 -0
  26. package/dashboard/dist/assets/mlx-DhWwjtMw.png +0 -0
  27. package/dashboard/dist/assets/ollama-Bt9O-2K_.png +0 -0
  28. package/dashboard/dist/assets/openrouter-CsJ_bD5Q.ico +0 -0
  29. package/dashboard/dist/assets/playwright-BldPFZgC.ico +0 -0
  30. package/dashboard/dist/assets/qwen-xykkX0_y.png +0 -0
  31. package/dashboard/dist/assets/react-vendor-C7Sl8SE7.js +9 -0
  32. package/dashboard/dist/assets/router-DHISdpPk.js +3 -0
  33. package/dashboard/dist/assets/shared-BIP_4k4I.js +1 -0
  34. package/dashboard/dist/favicon.svg +28 -0
  35. package/dashboard/dist/index.html +17 -0
  36. package/dist/agent/acp-client.js +261 -0
  37. package/dist/agent/auto-update.js +432 -0
  38. package/dist/agent/await-resume.js +50 -0
  39. package/dist/agent/cli/auth.js +325 -0
  40. package/dist/agent/cli/catalog.js +40 -0
  41. package/dist/agent/cli/detector.js +136 -0
  42. package/dist/agent/cli/index.js +7 -0
  43. package/dist/agent/cli/registry.js +33 -0
  44. package/dist/agent/driver.js +39 -0
  45. package/dist/agent/drivers/claude-tui.js +2297 -0
  46. package/dist/agent/drivers/claude.js +2689 -0
  47. package/dist/agent/drivers/codex.js +2210 -0
  48. package/dist/agent/drivers/gemini.js +1059 -0
  49. package/dist/agent/drivers/hermes.js +795 -0
  50. package/dist/agent/goal.js +274 -0
  51. package/dist/agent/handover.js +130 -0
  52. package/dist/agent/images.js +355 -0
  53. package/dist/agent/index.js +50 -0
  54. package/dist/agent/mcp/bridge.js +791 -0
  55. package/dist/agent/mcp/extensions.js +637 -0
  56. package/dist/agent/mcp/oauth.js +353 -0
  57. package/dist/agent/mcp/registry.js +119 -0
  58. package/dist/agent/mcp/session-server.js +229 -0
  59. package/dist/agent/mcp/tools/ask-user.js +113 -0
  60. package/dist/agent/mcp/tools/await-resume.js +77 -0
  61. package/dist/agent/mcp/tools/goal.js +144 -0
  62. package/dist/agent/mcp/tools/types.js +12 -0
  63. package/dist/agent/mcp/tools/workspace.js +212 -0
  64. package/dist/agent/npm.js +31 -0
  65. package/dist/agent/session.js +1206 -0
  66. package/dist/agent/skill-installer.js +160 -0
  67. package/dist/agent/skills.js +257 -0
  68. package/dist/agent/stream.js +743 -0
  69. package/dist/agent/types.js +13 -0
  70. package/dist/agent/utils.js +687 -0
  71. package/dist/bot/bot.js +2499 -0
  72. package/dist/bot/command-ui.js +633 -0
  73. package/dist/bot/commands.js +513 -0
  74. package/dist/bot/headless-bot.js +36 -0
  75. package/dist/bot/host.js +192 -0
  76. package/dist/bot/human-loop.js +168 -0
  77. package/dist/bot/menu.js +48 -0
  78. package/dist/bot/orchestration.js +79 -0
  79. package/dist/bot/render-shared.js +309 -0
  80. package/dist/bot/session-hub.js +361 -0
  81. package/dist/bot/session-status.js +55 -0
  82. package/dist/bot/streaming.js +309 -0
  83. package/dist/browser-profile.js +579 -0
  84. package/dist/browser-supervisor.js +249 -0
  85. package/dist/catalog/cli-tools.js +421 -0
  86. package/dist/catalog/index.js +21 -0
  87. package/dist/catalog/local-models.js +94 -0
  88. package/dist/catalog/mcp-servers.js +315 -0
  89. package/dist/catalog/skill-repos.js +173 -0
  90. package/dist/channels/base.js +55 -0
  91. package/dist/channels/dingtalk/bot.js +549 -0
  92. package/dist/channels/dingtalk/channel.js +268 -0
  93. package/dist/channels/discord/bot.js +552 -0
  94. package/dist/channels/discord/channel.js +245 -0
  95. package/dist/channels/feishu/bot.js +1275 -0
  96. package/dist/channels/feishu/channel.js +911 -0
  97. package/dist/channels/feishu/markdown.js +91 -0
  98. package/dist/channels/feishu/render.js +619 -0
  99. package/dist/channels/health.js +109 -0
  100. package/dist/channels/slack/bot.js +554 -0
  101. package/dist/channels/slack/channel.js +283 -0
  102. package/dist/channels/states.js +6 -0
  103. package/dist/channels/telegram/bot.js +1310 -0
  104. package/dist/channels/telegram/channel.js +820 -0
  105. package/dist/channels/telegram/directory.js +111 -0
  106. package/dist/channels/telegram/live-preview.js +220 -0
  107. package/dist/channels/telegram/render.js +384 -0
  108. package/dist/channels/wecom/bot.js +558 -0
  109. package/dist/channels/wecom/channel.js +479 -0
  110. package/dist/channels/weixin/api.js +520 -0
  111. package/dist/channels/weixin/bot.js +1000 -0
  112. package/dist/channels/weixin/channel.js +222 -0
  113. package/dist/cli/autostart.js +262 -0
  114. package/dist/cli/channel-supervisor.js +313 -0
  115. package/dist/cli/channels.js +54 -0
  116. package/dist/cli/main.js +726 -0
  117. package/dist/cli/onboarding.js +227 -0
  118. package/dist/cli/run.js +308 -0
  119. package/dist/cli/setup-wizard.js +235 -0
  120. package/dist/core/config/runtime-config.js +201 -0
  121. package/dist/core/config/user-config.js +510 -0
  122. package/dist/core/config/validation.js +521 -0
  123. package/dist/core/constants.js +400 -0
  124. package/dist/core/git.js +145 -0
  125. package/dist/core/legacy-compat.js +60 -0
  126. package/dist/core/logging.js +101 -0
  127. package/dist/core/platform.js +59 -0
  128. package/dist/core/process-control.js +315 -0
  129. package/dist/core/secrets/index.js +42 -0
  130. package/dist/core/secrets/inline-seal.js +60 -0
  131. package/dist/core/secrets/ref.js +33 -0
  132. package/dist/core/secrets/resolver.js +65 -0
  133. package/dist/core/secrets/store.js +63 -0
  134. package/dist/core/utils.js +233 -0
  135. package/dist/core/version.js +15 -0
  136. package/dist/dashboard/platform.js +219 -0
  137. package/dist/dashboard/routes/agents.js +450 -0
  138. package/dist/dashboard/routes/cli.js +174 -0
  139. package/dist/dashboard/routes/config.js +523 -0
  140. package/dist/dashboard/routes/extensions.js +745 -0
  141. package/dist/dashboard/routes/local-models.js +290 -0
  142. package/dist/dashboard/routes/models.js +324 -0
  143. package/dist/dashboard/routes/sessions.js +838 -0
  144. package/dist/dashboard/runtime.js +410 -0
  145. package/dist/dashboard/server.js +237 -0
  146. package/dist/dashboard/session-control.js +347 -0
  147. package/dist/model/catalog.js +104 -0
  148. package/dist/model/index.js +20 -0
  149. package/dist/model/injector.js +272 -0
  150. package/dist/model/provider-models.js +112 -0
  151. package/dist/model/store.js +212 -0
  152. package/dist/model/types.js +13 -0
  153. package/dist/model/validation.js +203 -0
  154. package/package.json +82 -0
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Discord channel transport — Gateway WebSocket (no public IP needed).
3
+ *
4
+ * Uses discord.js v14 with the bare minimum gateway intents:
5
+ * - Guilds, GuildMessages, MessageContent, DirectMessages
6
+ *
7
+ * IMPORTANT: For the bot to read message content in shared channels you must
8
+ * enable the "Message Content Intent" toggle in the Discord developer portal
9
+ * Bot page. Without it the gateway will silently emit empty `content`.
10
+ *
11
+ * Receives DMs and messages where the bot is mentioned. Self-authored
12
+ * messages are filtered out before dispatch.
13
+ */
14
+ import { Client, Events, GatewayIntentBits, Partials, } from 'discord.js';
15
+ import { Channel, DEFAULT_CHANNEL_CAPABILITIES, splitText, sleep, } from '../base.js';
16
+ import { DISCORD_LIMITS } from '../../core/constants.js';
17
+ import { writeScopedLog } from '../../core/logging.js';
18
+ const DISCORD_MAX = DISCORD_LIMITS.maxMessageLength;
19
+ function describeError(err) {
20
+ return err instanceof Error ? err.message : String(err ?? 'unknown error');
21
+ }
22
+ export class DiscordChannel extends Channel {
23
+ capabilities = {
24
+ ...DEFAULT_CHANNEL_CAPABILITIES,
25
+ editMessages: true,
26
+ };
27
+ knownChats = new Set();
28
+ botToken;
29
+ allowedChatIds;
30
+ requireMention;
31
+ client;
32
+ botUserId = null;
33
+ running = false;
34
+ listenResolve = null;
35
+ messageHandlers = new Set();
36
+ errorHandlers = new Set();
37
+ constructor(opts) {
38
+ super();
39
+ this.botToken = opts.botToken;
40
+ this.allowedChatIds = opts.allowedChatIds;
41
+ this.requireMention = opts.requireMentionInChannel ?? true;
42
+ }
43
+ onMessage(handler) { this.messageHandlers.add(handler); return this; }
44
+ onError(handler) { this.errorHandlers.add(handler); return this; }
45
+ // ========================================================================
46
+ // Lifecycle
47
+ // ========================================================================
48
+ async connect() {
49
+ this.client = new Client({
50
+ intents: [
51
+ GatewayIntentBits.Guilds,
52
+ GatewayIntentBits.GuildMessages,
53
+ GatewayIntentBits.MessageContent,
54
+ GatewayIntentBits.DirectMessages,
55
+ ],
56
+ partials: [Partials.Channel, Partials.Message],
57
+ });
58
+ let resolveReady = null;
59
+ let rejectReady = null;
60
+ const ready = new Promise((resolve, reject) => {
61
+ resolveReady = resolve;
62
+ rejectReady = reject;
63
+ });
64
+ this.client.once(Events.ClientReady, () => resolveReady?.());
65
+ this.client.once(Events.Error, err => rejectReady?.(err instanceof Error ? err : new Error(describeError(err))));
66
+ let lastErr = null;
67
+ for (let attempt = 1; attempt <= 5; attempt++) {
68
+ try {
69
+ await this.client.login(this.botToken);
70
+ await ready;
71
+ const me = this.client.user;
72
+ if (!me)
73
+ throw new Error('Discord client missing user after ready');
74
+ this.botUserId = me.id;
75
+ this.bot = {
76
+ id: me.id,
77
+ username: me.username || '',
78
+ displayName: me.displayName || me.username || 'discord-bot',
79
+ };
80
+ return this.bot;
81
+ }
82
+ catch (err) {
83
+ lastErr = err;
84
+ try {
85
+ await this.client.destroy();
86
+ }
87
+ catch { }
88
+ if (attempt >= 5)
89
+ break;
90
+ await sleep(Math.min(1000 * attempt, 5_000));
91
+ }
92
+ }
93
+ throw new Error(`Discord connect failed: ${describeError(lastErr)}`);
94
+ }
95
+ async listen() {
96
+ this.running = true;
97
+ this.client.on(Events.MessageCreate, (msg) => {
98
+ void this.dispatchMessage(msg).catch(error => {
99
+ this.emitError(error instanceof Error ? error : new Error(describeError(error)));
100
+ });
101
+ });
102
+ this.client.on(Events.Error, err => {
103
+ this.emitError(err instanceof Error ? err : new Error(describeError(err)));
104
+ });
105
+ this.client.on(Events.ShardDisconnect, () => {
106
+ this.debug('[gateway] shard disconnected — discord.js will auto-reconnect');
107
+ });
108
+ if (!this.running)
109
+ return;
110
+ await new Promise(resolve => {
111
+ this.listenResolve = resolve;
112
+ if (!this.running)
113
+ resolve();
114
+ });
115
+ }
116
+ disconnect() {
117
+ this.running = false;
118
+ try {
119
+ void this.client?.destroy();
120
+ }
121
+ catch { }
122
+ this.listenResolve?.();
123
+ this.listenResolve = null;
124
+ }
125
+ // ========================================================================
126
+ // Outgoing primitives
127
+ // ========================================================================
128
+ async send(chatId, text, opts = {}) {
129
+ const channelId = String(chatId);
130
+ const channel = await this.fetchTextChannel(channelId);
131
+ const chunks = splitText((text || '').trim() || '(empty)', DISCORD_MAX);
132
+ let lastId = null;
133
+ for (let i = 0; i < chunks.length; i++) {
134
+ const chunk = chunks[i];
135
+ const payload = { content: chunk };
136
+ if (opts.replyTo)
137
+ payload.reply = { messageReference: String(opts.replyTo), failIfNotExists: false };
138
+ const sent = await channel.send(payload);
139
+ lastId = sent.id;
140
+ }
141
+ return lastId;
142
+ }
143
+ async editMessage(chatId, msgId, text, _opts) {
144
+ const trimmed = String(text);
145
+ if (!trimmed.trim())
146
+ return;
147
+ const channel = await this.fetchTextChannel(String(chatId));
148
+ const truncated = trimmed.length > DISCORD_MAX ? trimmed.slice(0, DISCORD_MAX) + '\n…(truncated)' : trimmed;
149
+ try {
150
+ const message = await channel.messages.fetch(String(msgId));
151
+ await message.edit({ content: truncated });
152
+ }
153
+ catch (err) {
154
+ const detail = describeError(err).toLowerCase();
155
+ if (detail.includes('unknown message') || detail.includes('cannot edit'))
156
+ return;
157
+ throw err;
158
+ }
159
+ }
160
+ async deleteMessage(chatId, msgId) {
161
+ try {
162
+ const channel = await this.fetchTextChannel(String(chatId));
163
+ const message = await channel.messages.fetch(String(msgId));
164
+ await message.delete();
165
+ }
166
+ catch { }
167
+ }
168
+ async sendTyping(chatId, _opts) {
169
+ try {
170
+ const channel = await this.fetchTextChannel(String(chatId));
171
+ if (typeof channel.sendTyping === 'function') {
172
+ await channel.sendTyping();
173
+ }
174
+ }
175
+ catch { }
176
+ }
177
+ // ========================================================================
178
+ // Internal dispatch
179
+ // ========================================================================
180
+ async dispatchMessage(msg) {
181
+ if (msg.author?.bot)
182
+ return;
183
+ if (this.botUserId && msg.author?.id === this.botUserId)
184
+ return;
185
+ const channelId = msg.channelId;
186
+ const messageId = msg.id;
187
+ const userId = msg.author?.id || '';
188
+ if (!channelId || !messageId || !userId)
189
+ return;
190
+ if (!this.isAllowed(channelId))
191
+ return;
192
+ this.knownChats.add(channelId);
193
+ const isDm = msg.channel?.isDMBased?.() ?? false;
194
+ const mentioned = this.botUserId ? msg.mentions?.users?.has(this.botUserId) === true : false;
195
+ if (!isDm && this.requireMention && !mentioned)
196
+ return;
197
+ let cleaned = String(msg.content || '');
198
+ if (this.botUserId) {
199
+ cleaned = cleaned.replace(new RegExp(`<@!?${this.botUserId}>`, 'g'), '').trim();
200
+ }
201
+ const ctx = {
202
+ chatId: channelId,
203
+ messageId,
204
+ from: { userId, username: msg.author?.username || undefined },
205
+ reply: (text, opts) => this.send(channelId, text, { ...opts, replyTo: opts?.replyTo ?? messageId }),
206
+ editReply: (replyMsgId, text, opts) => this.editMessage(channelId, replyMsgId, text, opts),
207
+ channel: this,
208
+ raw: msg,
209
+ };
210
+ const payload = { text: cleaned, files: [] };
211
+ for (const handler of this.messageHandlers) {
212
+ try {
213
+ await handler(payload, ctx);
214
+ }
215
+ catch (error) {
216
+ this.emitError(error instanceof Error ? error : new Error(describeError(error)));
217
+ }
218
+ }
219
+ }
220
+ isAllowed(chatId) {
221
+ if (!this.allowedChatIds?.size)
222
+ return true;
223
+ return this.allowedChatIds.has(chatId);
224
+ }
225
+ async fetchTextChannel(channelId) {
226
+ const cached = this.client.channels.cache.get(channelId);
227
+ if (cached && 'send' in cached)
228
+ return cached;
229
+ const fetched = await this.client.channels.fetch(channelId);
230
+ if (!fetched || !('send' in fetched)) {
231
+ throw new Error(`Discord channel ${channelId} is not text-based`);
232
+ }
233
+ return fetched;
234
+ }
235
+ emitError(error) {
236
+ for (const handler of this.errorHandlers) {
237
+ try {
238
+ handler(error);
239
+ }
240
+ catch { }
241
+ }
242
+ }
243
+ debug(msg) { this.log(msg, 'debug'); }
244
+ log(msg, level = 'info') { writeScopedLog('discord', msg, { level }); }
245
+ }