@cremini/skillpack 1.2.4 → 1.2.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +502 -60
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -323,6 +323,20 @@ var init_commands = __esm({
|
|
|
323
323
|
}
|
|
324
324
|
});
|
|
325
325
|
|
|
326
|
+
// src/runtime/adapters/types.ts
|
|
327
|
+
var types_exports = {};
|
|
328
|
+
__export(types_exports, {
|
|
329
|
+
isMessageSender: () => isMessageSender
|
|
330
|
+
});
|
|
331
|
+
function isMessageSender(adapter) {
|
|
332
|
+
return typeof adapter.sendMessage === "function";
|
|
333
|
+
}
|
|
334
|
+
var init_types = __esm({
|
|
335
|
+
"src/runtime/adapters/types.ts"() {
|
|
336
|
+
"use strict";
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
326
340
|
// src/runtime/adapters/markdown.ts
|
|
327
341
|
function unwrapMarkdownSourceBlocks(text) {
|
|
328
342
|
return text.replace(
|
|
@@ -443,7 +457,7 @@ var telegram_exports = {};
|
|
|
443
457
|
__export(telegram_exports, {
|
|
444
458
|
TelegramAdapter: () => TelegramAdapter
|
|
445
459
|
});
|
|
446
|
-
import
|
|
460
|
+
import fs13 from "fs";
|
|
447
461
|
import TelegramBot from "node-telegram-bot-api";
|
|
448
462
|
var MAX_MESSAGE_LENGTH, ACK_REACTION, TelegramAdapter;
|
|
449
463
|
var init_telegram = __esm({
|
|
@@ -463,12 +477,14 @@ var init_telegram = __esm({
|
|
|
463
477
|
agent = null;
|
|
464
478
|
options;
|
|
465
479
|
rootDir = "";
|
|
480
|
+
ipcBroadcaster = null;
|
|
466
481
|
constructor(options) {
|
|
467
482
|
this.options = options;
|
|
468
483
|
}
|
|
469
484
|
async start(ctx) {
|
|
470
485
|
this.agent = ctx.agent;
|
|
471
486
|
this.rootDir = ctx.rootDir;
|
|
487
|
+
this.ipcBroadcaster = ctx.ipcBroadcaster ?? null;
|
|
472
488
|
this.bot = new TelegramBot(this.options.token, { polling: true });
|
|
473
489
|
this.bot.on("message", (msg) => {
|
|
474
490
|
this.handleTelegramMessage(msg).catch((err) => {
|
|
@@ -510,6 +526,15 @@ var init_telegram = __esm({
|
|
|
510
526
|
const messageId = msg.message_id;
|
|
511
527
|
const text = (msg.text || msg.caption || "").trim();
|
|
512
528
|
const channelId = `telegram-${chatId}`;
|
|
529
|
+
this.ipcBroadcaster?.broadcastInbound(
|
|
530
|
+
channelId,
|
|
531
|
+
"telegram",
|
|
532
|
+
{
|
|
533
|
+
id: String(msg.from?.id || ""),
|
|
534
|
+
username: msg.from?.username || msg.from?.first_name || ""
|
|
535
|
+
},
|
|
536
|
+
text
|
|
537
|
+
);
|
|
513
538
|
const attachments = await this.extractAttachments(msg, channelId);
|
|
514
539
|
if (!text && attachments.length === 0) return;
|
|
515
540
|
await this.tryAckReaction(chatId, messageId);
|
|
@@ -539,6 +564,7 @@ var init_telegram = __esm({
|
|
|
539
564
|
});
|
|
540
565
|
break;
|
|
541
566
|
}
|
|
567
|
+
this.ipcBroadcaster?.broadcastAgentEvent(channelId, event);
|
|
542
568
|
};
|
|
543
569
|
try {
|
|
544
570
|
const userText = text || "(User sent an attachment)";
|
|
@@ -749,7 +775,7 @@ var init_telegram = __esm({
|
|
|
749
775
|
async sendFileSafe(chatId, filePath, caption) {
|
|
750
776
|
if (!this.bot) return;
|
|
751
777
|
try {
|
|
752
|
-
if (!
|
|
778
|
+
if (!fs13.existsSync(filePath)) {
|
|
753
779
|
console.error(`[Telegram] File not found for sending: ${filePath}`);
|
|
754
780
|
return;
|
|
755
781
|
}
|
|
@@ -769,8 +795,8 @@ var slack_exports = {};
|
|
|
769
795
|
__export(slack_exports, {
|
|
770
796
|
SlackAdapter: () => SlackAdapter
|
|
771
797
|
});
|
|
772
|
-
import
|
|
773
|
-
import
|
|
798
|
+
import fs14 from "fs";
|
|
799
|
+
import path13 from "path";
|
|
774
800
|
import { App, LogLevel } from "@slack/bolt";
|
|
775
801
|
var INLINE_COMMANDS, SLASH_COMMANDS, MAX_MESSAGE_LENGTH2, ACK_REACTION2, PROCESSING_MESSAGE, SlackAdapter;
|
|
776
802
|
var init_slack = __esm({
|
|
@@ -801,12 +827,14 @@ var init_slack = __esm({
|
|
|
801
827
|
botUserId = null;
|
|
802
828
|
lastThreadByChannel = /* @__PURE__ */ new Map();
|
|
803
829
|
rootDir = "";
|
|
830
|
+
ipcBroadcaster = null;
|
|
804
831
|
constructor(options) {
|
|
805
832
|
this.options = options;
|
|
806
833
|
}
|
|
807
834
|
async start(ctx) {
|
|
808
835
|
this.agent = ctx.agent;
|
|
809
836
|
this.rootDir = ctx.rootDir;
|
|
837
|
+
this.ipcBroadcaster = ctx.ipcBroadcaster ?? null;
|
|
810
838
|
this.app = new App({
|
|
811
839
|
token: this.options.botToken,
|
|
812
840
|
appToken: this.options.appToken,
|
|
@@ -892,6 +920,15 @@ var init_slack = __esm({
|
|
|
892
920
|
const teamId = this.getTeamId(body, context);
|
|
893
921
|
const channelId = `slack-dm-${teamId}-${event.channel}`;
|
|
894
922
|
const route = { channel: event.channel };
|
|
923
|
+
this.ipcBroadcaster?.broadcastInbound(
|
|
924
|
+
channelId,
|
|
925
|
+
"slack",
|
|
926
|
+
{
|
|
927
|
+
id: String(event.user || ""),
|
|
928
|
+
username: String(event.user || "")
|
|
929
|
+
},
|
|
930
|
+
text
|
|
931
|
+
);
|
|
895
932
|
const attachments = await this.extractSlackFiles(event, channelId, client);
|
|
896
933
|
if (!text && attachments.length === 0) return;
|
|
897
934
|
await this.tryAckReaction(client, event);
|
|
@@ -922,6 +959,15 @@ var init_slack = __esm({
|
|
|
922
959
|
threadTs
|
|
923
960
|
);
|
|
924
961
|
const text = this.stripBotMention(event.text || "").trim();
|
|
962
|
+
this.ipcBroadcaster?.broadcastInbound(
|
|
963
|
+
channelId,
|
|
964
|
+
"slack",
|
|
965
|
+
{
|
|
966
|
+
id: String(event.user || ""),
|
|
967
|
+
username: String(event.user || "")
|
|
968
|
+
},
|
|
969
|
+
text
|
|
970
|
+
);
|
|
925
971
|
const attachments = await this.extractSlackFiles(event, channelId, client);
|
|
926
972
|
if (!text && attachments.length === 0) {
|
|
927
973
|
await this.sendSafe(
|
|
@@ -981,6 +1027,7 @@ var init_slack = __esm({
|
|
|
981
1027
|
caption: event.caption
|
|
982
1028
|
});
|
|
983
1029
|
}
|
|
1030
|
+
this.ipcBroadcaster?.broadcastAgentEvent(channelId, event);
|
|
984
1031
|
};
|
|
985
1032
|
try {
|
|
986
1033
|
const result = await this.agent.handleMessage(
|
|
@@ -1384,12 +1431,12 @@ var init_slack = __esm({
|
|
|
1384
1431
|
*/
|
|
1385
1432
|
async sendFileSafe(client, route, filePath, caption) {
|
|
1386
1433
|
try {
|
|
1387
|
-
if (!
|
|
1434
|
+
if (!fs14.existsSync(filePath)) {
|
|
1388
1435
|
console.error(`[Slack] File not found for sending: ${filePath}`);
|
|
1389
1436
|
return;
|
|
1390
1437
|
}
|
|
1391
|
-
const filename =
|
|
1392
|
-
const fileContent =
|
|
1438
|
+
const filename = path13.basename(filePath);
|
|
1439
|
+
const fileContent = fs14.readFileSync(filePath);
|
|
1393
1440
|
await client.files.uploadV2({
|
|
1394
1441
|
channel_id: route.channel,
|
|
1395
1442
|
thread_ts: route.threadTs,
|
|
@@ -1406,20 +1453,6 @@ var init_slack = __esm({
|
|
|
1406
1453
|
}
|
|
1407
1454
|
});
|
|
1408
1455
|
|
|
1409
|
-
// src/runtime/adapters/types.ts
|
|
1410
|
-
var types_exports = {};
|
|
1411
|
-
__export(types_exports, {
|
|
1412
|
-
isMessageSender: () => isMessageSender
|
|
1413
|
-
});
|
|
1414
|
-
function isMessageSender(adapter) {
|
|
1415
|
-
return typeof adapter.sendMessage === "function";
|
|
1416
|
-
}
|
|
1417
|
-
var init_types = __esm({
|
|
1418
|
-
"src/runtime/adapters/types.ts"() {
|
|
1419
|
-
"use strict";
|
|
1420
|
-
}
|
|
1421
|
-
});
|
|
1422
|
-
|
|
1423
1456
|
// src/runtime/adapters/scheduler.ts
|
|
1424
1457
|
var scheduler_exports = {};
|
|
1425
1458
|
__export(scheduler_exports, {
|
|
@@ -2430,15 +2463,15 @@ async function interactiveCreate(workDir) {
|
|
|
2430
2463
|
}
|
|
2431
2464
|
|
|
2432
2465
|
// src/commands/run.ts
|
|
2433
|
-
import
|
|
2434
|
-
import
|
|
2466
|
+
import path15 from "path";
|
|
2467
|
+
import fs16 from "fs";
|
|
2435
2468
|
import inquirer2 from "inquirer";
|
|
2436
2469
|
import chalk4 from "chalk";
|
|
2437
2470
|
|
|
2438
2471
|
// src/runtime/server.ts
|
|
2439
2472
|
import express from "express";
|
|
2440
|
-
import
|
|
2441
|
-
import
|
|
2473
|
+
import path14 from "path";
|
|
2474
|
+
import fs15 from "fs";
|
|
2442
2475
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2443
2476
|
import { createServer } from "http";
|
|
2444
2477
|
import { exec } from "child_process";
|
|
@@ -5835,6 +5868,9 @@ ${text}`;
|
|
|
5835
5868
|
/** Reserved: restore a historical session */
|
|
5836
5869
|
async restoreSession(_sessionId) {
|
|
5837
5870
|
}
|
|
5871
|
+
getActiveChannelIds() {
|
|
5872
|
+
return Array.from(this.channels.keys());
|
|
5873
|
+
}
|
|
5838
5874
|
};
|
|
5839
5875
|
|
|
5840
5876
|
// src/runtime/adapters/web.ts
|
|
@@ -5868,9 +5904,11 @@ var WebAdapter = class {
|
|
|
5868
5904
|
name = "web";
|
|
5869
5905
|
wss = null;
|
|
5870
5906
|
agent = null;
|
|
5907
|
+
ipcBroadcaster = null;
|
|
5871
5908
|
async start(ctx) {
|
|
5872
5909
|
const { agent, server, app, rootDir, lifecycle } = ctx;
|
|
5873
5910
|
this.agent = agent;
|
|
5911
|
+
this.ipcBroadcaster = ctx.ipcBroadcaster ?? null;
|
|
5874
5912
|
const currentConf = configManager.getConfig();
|
|
5875
5913
|
let apiKey = currentConf.apiKey || "";
|
|
5876
5914
|
let currentProvider = currentConf.provider || "openai";
|
|
@@ -6138,6 +6176,7 @@ var WebAdapter = class {
|
|
|
6138
6176
|
}
|
|
6139
6177
|
const onEvent = (event) => {
|
|
6140
6178
|
sendWsEvent(ws, event);
|
|
6179
|
+
this.ipcBroadcaster?.broadcastAgentEvent(channelId, event);
|
|
6141
6180
|
};
|
|
6142
6181
|
const result = await agent.handleMessage("web", channelId, text, onEvent);
|
|
6143
6182
|
if (result.errorMessage) {
|
|
@@ -6155,6 +6194,367 @@ var WebAdapter = class {
|
|
|
6155
6194
|
}
|
|
6156
6195
|
};
|
|
6157
6196
|
|
|
6197
|
+
// src/runtime/adapters/ipc.ts
|
|
6198
|
+
init_config();
|
|
6199
|
+
|
|
6200
|
+
// src/runtime/services/conversation.ts
|
|
6201
|
+
import fs11 from "fs";
|
|
6202
|
+
import path11 from "path";
|
|
6203
|
+
import {
|
|
6204
|
+
parseSessionEntries
|
|
6205
|
+
} from "@mariozechner/pi-coding-agent";
|
|
6206
|
+
var ConversationService = class {
|
|
6207
|
+
constructor(rootDir) {
|
|
6208
|
+
this.rootDir = rootDir;
|
|
6209
|
+
}
|
|
6210
|
+
/**
|
|
6211
|
+
* Scan data/sessions and return conversation summaries sorted by recency.
|
|
6212
|
+
*/
|
|
6213
|
+
listConversations(activeChannels) {
|
|
6214
|
+
const sessionsDir = path11.resolve(this.rootDir, "data", "sessions");
|
|
6215
|
+
const channelIds = new Set(activeChannels);
|
|
6216
|
+
if (fs11.existsSync(sessionsDir)) {
|
|
6217
|
+
for (const entry of fs11.readdirSync(sessionsDir)) {
|
|
6218
|
+
const channelDir = path11.join(sessionsDir, entry);
|
|
6219
|
+
try {
|
|
6220
|
+
if (fs11.statSync(channelDir).isDirectory()) {
|
|
6221
|
+
channelIds.add(entry);
|
|
6222
|
+
}
|
|
6223
|
+
} catch {
|
|
6224
|
+
}
|
|
6225
|
+
}
|
|
6226
|
+
}
|
|
6227
|
+
const results = [];
|
|
6228
|
+
for (const channelId of channelIds) {
|
|
6229
|
+
const channelDir = path11.join(sessionsDir, channelId);
|
|
6230
|
+
const sessionFile = this.findLatestSessionFile(channelDir);
|
|
6231
|
+
let messageCount = 0;
|
|
6232
|
+
let lastMessageAt = "";
|
|
6233
|
+
let lastMessagePreview = "";
|
|
6234
|
+
if (sessionFile) {
|
|
6235
|
+
const entries = this.loadEntries(sessionFile);
|
|
6236
|
+
const messages = entries.filter(
|
|
6237
|
+
(entry) => entry.type === "message"
|
|
6238
|
+
);
|
|
6239
|
+
messageCount = messages.length;
|
|
6240
|
+
const lastMessage = messages[messages.length - 1];
|
|
6241
|
+
if (lastMessage) {
|
|
6242
|
+
lastMessageAt = lastMessage.timestamp;
|
|
6243
|
+
lastMessagePreview = this.extractTextPreview(lastMessage, 100);
|
|
6244
|
+
}
|
|
6245
|
+
}
|
|
6246
|
+
results.push({
|
|
6247
|
+
channelId,
|
|
6248
|
+
platform: this.detectPlatform(channelId),
|
|
6249
|
+
sessionFile,
|
|
6250
|
+
messageCount,
|
|
6251
|
+
lastMessageAt,
|
|
6252
|
+
lastMessagePreview
|
|
6253
|
+
});
|
|
6254
|
+
}
|
|
6255
|
+
return results.sort((a, b) => {
|
|
6256
|
+
const recency = (b.lastMessageAt || "").localeCompare(a.lastMessageAt || "");
|
|
6257
|
+
if (recency !== 0) return recency;
|
|
6258
|
+
return a.channelId.localeCompare(b.channelId);
|
|
6259
|
+
});
|
|
6260
|
+
}
|
|
6261
|
+
/**
|
|
6262
|
+
* Load latest messages for a channel in a simplified format.
|
|
6263
|
+
*/
|
|
6264
|
+
getMessages(channelId, limit = 100) {
|
|
6265
|
+
const channelDir = path11.resolve(
|
|
6266
|
+
this.rootDir,
|
|
6267
|
+
"data",
|
|
6268
|
+
"sessions",
|
|
6269
|
+
channelId
|
|
6270
|
+
);
|
|
6271
|
+
const sessionFile = this.findLatestSessionFile(channelDir);
|
|
6272
|
+
if (!sessionFile) return [];
|
|
6273
|
+
const safeLimit = Number.isFinite(limit) ? Math.max(0, Math.floor(limit)) : 100;
|
|
6274
|
+
if (safeLimit === 0) return [];
|
|
6275
|
+
const entries = this.loadEntries(sessionFile);
|
|
6276
|
+
const messages = [];
|
|
6277
|
+
for (const entry of entries) {
|
|
6278
|
+
if (entry.type !== "message") continue;
|
|
6279
|
+
const role = entry.message?.role;
|
|
6280
|
+
if (role !== "user" && role !== "assistant") continue;
|
|
6281
|
+
const text = this.extractText(entry.message);
|
|
6282
|
+
if (!text) continue;
|
|
6283
|
+
const toolCalls = role === "assistant" ? this.extractToolCallSummaries(entry.message) : void 0;
|
|
6284
|
+
messages.push({
|
|
6285
|
+
id: entry.id,
|
|
6286
|
+
role,
|
|
6287
|
+
text,
|
|
6288
|
+
timestamp: entry.timestamp,
|
|
6289
|
+
toolCalls
|
|
6290
|
+
});
|
|
6291
|
+
}
|
|
6292
|
+
return messages.slice(-safeLimit);
|
|
6293
|
+
}
|
|
6294
|
+
findLatestSessionFile(channelDir) {
|
|
6295
|
+
if (!fs11.existsSync(channelDir)) return null;
|
|
6296
|
+
let stats;
|
|
6297
|
+
try {
|
|
6298
|
+
stats = fs11.statSync(channelDir);
|
|
6299
|
+
} catch {
|
|
6300
|
+
return null;
|
|
6301
|
+
}
|
|
6302
|
+
if (!stats.isDirectory()) return null;
|
|
6303
|
+
const files = fs11.readdirSync(channelDir).filter((file) => file.endsWith(".jsonl")).sort((a, b) => b.localeCompare(a));
|
|
6304
|
+
return files[0] ? path11.join(channelDir, files[0]) : null;
|
|
6305
|
+
}
|
|
6306
|
+
loadEntries(filePath) {
|
|
6307
|
+
try {
|
|
6308
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
6309
|
+
const fileEntries = parseSessionEntries(content);
|
|
6310
|
+
return fileEntries.filter((entry) => entry.type !== "session");
|
|
6311
|
+
} catch (err) {
|
|
6312
|
+
console.warn(`[ConversationService] Failed to load ${filePath}:`, err);
|
|
6313
|
+
return [];
|
|
6314
|
+
}
|
|
6315
|
+
}
|
|
6316
|
+
extractText(message) {
|
|
6317
|
+
if (!message?.content) return "";
|
|
6318
|
+
if (typeof message.content === "string") return message.content.trim();
|
|
6319
|
+
if (!Array.isArray(message.content)) return "";
|
|
6320
|
+
return message.content.filter((item) => item?.type === "text").map((item) => typeof item?.text === "string" ? item.text : "").join("").trim();
|
|
6321
|
+
}
|
|
6322
|
+
extractTextPreview(entry, maxLen) {
|
|
6323
|
+
const text = this.extractText(entry.message);
|
|
6324
|
+
return text.length > maxLen ? `${text.slice(0, maxLen)}\u2026` : text;
|
|
6325
|
+
}
|
|
6326
|
+
extractToolCallSummaries(message) {
|
|
6327
|
+
if (!Array.isArray(message?.content)) return void 0;
|
|
6328
|
+
const toolCalls = message.content.filter((item) => item?.type === "toolCall").map((item) => ({
|
|
6329
|
+
name: typeof item?.name === "string" && item.name ? item.name : "unknown",
|
|
6330
|
+
isError: false
|
|
6331
|
+
}));
|
|
6332
|
+
return toolCalls.length > 0 ? toolCalls : void 0;
|
|
6333
|
+
}
|
|
6334
|
+
detectPlatform(channelId) {
|
|
6335
|
+
if (channelId.startsWith("telegram-")) return "telegram";
|
|
6336
|
+
if (channelId.startsWith("slack-")) return "slack";
|
|
6337
|
+
if (channelId.startsWith("scheduler-")) return "scheduler";
|
|
6338
|
+
return "web";
|
|
6339
|
+
}
|
|
6340
|
+
};
|
|
6341
|
+
|
|
6342
|
+
// src/runtime/adapters/ipc.ts
|
|
6343
|
+
init_types();
|
|
6344
|
+
var IpcAdapter = class {
|
|
6345
|
+
name = "ipc";
|
|
6346
|
+
agent = null;
|
|
6347
|
+
rootDir = "";
|
|
6348
|
+
adapterMap = null;
|
|
6349
|
+
conversationService = null;
|
|
6350
|
+
messageListener;
|
|
6351
|
+
started = false;
|
|
6352
|
+
async start(ctx) {
|
|
6353
|
+
if (typeof process.send !== "function") {
|
|
6354
|
+
return;
|
|
6355
|
+
}
|
|
6356
|
+
this.agent = ctx.agent;
|
|
6357
|
+
this.rootDir = ctx.rootDir;
|
|
6358
|
+
this.adapterMap = ctx.adapterMap ?? null;
|
|
6359
|
+
this.conversationService = new ConversationService(ctx.rootDir);
|
|
6360
|
+
this.messageListener = (message) => {
|
|
6361
|
+
if (!this.isIpcRequest(message)) return;
|
|
6362
|
+
void this.handleRequest(message);
|
|
6363
|
+
};
|
|
6364
|
+
process.on("message", this.messageListener);
|
|
6365
|
+
this.started = true;
|
|
6366
|
+
console.log("[IpcAdapter] Started");
|
|
6367
|
+
}
|
|
6368
|
+
async stop() {
|
|
6369
|
+
if (this.messageListener) {
|
|
6370
|
+
process.off("message", this.messageListener);
|
|
6371
|
+
this.messageListener = void 0;
|
|
6372
|
+
}
|
|
6373
|
+
if (this.started) {
|
|
6374
|
+
console.log("[IpcAdapter] Stopped");
|
|
6375
|
+
}
|
|
6376
|
+
this.started = false;
|
|
6377
|
+
}
|
|
6378
|
+
notifyReady(port) {
|
|
6379
|
+
this.sendIpc({
|
|
6380
|
+
type: "ready",
|
|
6381
|
+
port
|
|
6382
|
+
});
|
|
6383
|
+
}
|
|
6384
|
+
broadcastInbound(channelId, platform, sender, text) {
|
|
6385
|
+
this.sendIpc({
|
|
6386
|
+
type: "inbound_message",
|
|
6387
|
+
channelId,
|
|
6388
|
+
platform,
|
|
6389
|
+
sender,
|
|
6390
|
+
text,
|
|
6391
|
+
timestamp: Date.now()
|
|
6392
|
+
});
|
|
6393
|
+
}
|
|
6394
|
+
broadcastAgentEvent(channelId, event) {
|
|
6395
|
+
this.sendIpc({
|
|
6396
|
+
type: "agent_event",
|
|
6397
|
+
channelId,
|
|
6398
|
+
event
|
|
6399
|
+
});
|
|
6400
|
+
}
|
|
6401
|
+
isIpcRequest(message) {
|
|
6402
|
+
if (!message || typeof message !== "object") return false;
|
|
6403
|
+
const maybe = message;
|
|
6404
|
+
return typeof maybe.id === "string" && typeof maybe.type === "string";
|
|
6405
|
+
}
|
|
6406
|
+
async handleRequest(request) {
|
|
6407
|
+
if (!this.agent || !this.conversationService) {
|
|
6408
|
+
this.replyError(request.id, "IPC adapter is not ready yet");
|
|
6409
|
+
return;
|
|
6410
|
+
}
|
|
6411
|
+
try {
|
|
6412
|
+
switch (request.type) {
|
|
6413
|
+
case "get_conversations": {
|
|
6414
|
+
const activeChannels = new Set(this.agent.getActiveChannelIds());
|
|
6415
|
+
const conversations = this.conversationService.listConversations(activeChannels);
|
|
6416
|
+
this.reply(request.id, conversations);
|
|
6417
|
+
return;
|
|
6418
|
+
}
|
|
6419
|
+
case "get_messages": {
|
|
6420
|
+
if (!request.channelId || typeof request.channelId !== "string") {
|
|
6421
|
+
this.replyError(request.id, "channelId is required");
|
|
6422
|
+
return;
|
|
6423
|
+
}
|
|
6424
|
+
const messages = this.conversationService.getMessages(
|
|
6425
|
+
request.channelId,
|
|
6426
|
+
request.limit ?? 100
|
|
6427
|
+
);
|
|
6428
|
+
this.reply(request.id, messages);
|
|
6429
|
+
return;
|
|
6430
|
+
}
|
|
6431
|
+
case "send_message": {
|
|
6432
|
+
if (!request.channelId || typeof request.channelId !== "string") {
|
|
6433
|
+
this.replyError(request.id, "channelId is required");
|
|
6434
|
+
return;
|
|
6435
|
+
}
|
|
6436
|
+
if (typeof request.text !== "string") {
|
|
6437
|
+
this.replyError(request.id, "text is required");
|
|
6438
|
+
return;
|
|
6439
|
+
}
|
|
6440
|
+
const platform = this.detectPlatform(request.channelId);
|
|
6441
|
+
let fullText = "";
|
|
6442
|
+
const result = await this.agent.handleMessage(
|
|
6443
|
+
platform,
|
|
6444
|
+
request.channelId,
|
|
6445
|
+
request.text,
|
|
6446
|
+
(event) => {
|
|
6447
|
+
if (event.type === "text_delta") {
|
|
6448
|
+
fullText += event.delta;
|
|
6449
|
+
}
|
|
6450
|
+
this.broadcastAgentEvent(request.channelId, event);
|
|
6451
|
+
}
|
|
6452
|
+
);
|
|
6453
|
+
if (fullText.trim() && platform !== "web" && platform !== "scheduler") {
|
|
6454
|
+
const adapter = this.adapterMap?.get(platform);
|
|
6455
|
+
if (adapter && isMessageSender(adapter)) {
|
|
6456
|
+
await adapter.sendMessage(request.channelId, fullText);
|
|
6457
|
+
}
|
|
6458
|
+
}
|
|
6459
|
+
this.reply(request.id, {
|
|
6460
|
+
...result,
|
|
6461
|
+
text: fullText
|
|
6462
|
+
});
|
|
6463
|
+
return;
|
|
6464
|
+
}
|
|
6465
|
+
case "command": {
|
|
6466
|
+
if (!request.channelId || typeof request.channelId !== "string") {
|
|
6467
|
+
this.replyError(request.id, "channelId is required");
|
|
6468
|
+
return;
|
|
6469
|
+
}
|
|
6470
|
+
const result = await this.agent.handleCommand(request.command, request.channelId);
|
|
6471
|
+
this.reply(request.id, result);
|
|
6472
|
+
return;
|
|
6473
|
+
}
|
|
6474
|
+
case "get_config": {
|
|
6475
|
+
this.reply(request.id, configManager.getConfig());
|
|
6476
|
+
return;
|
|
6477
|
+
}
|
|
6478
|
+
case "update_config": {
|
|
6479
|
+
configManager.save(this.rootDir, request.updates || {});
|
|
6480
|
+
const updated = configManager.getConfig();
|
|
6481
|
+
const provider = updated.provider || "openai";
|
|
6482
|
+
this.agent.updateAuth(provider, updated.apiKey);
|
|
6483
|
+
this.reply(request.id, updated);
|
|
6484
|
+
return;
|
|
6485
|
+
}
|
|
6486
|
+
case "get_status": {
|
|
6487
|
+
this.reply(request.id, {
|
|
6488
|
+
status: "running",
|
|
6489
|
+
pid: process.pid
|
|
6490
|
+
});
|
|
6491
|
+
return;
|
|
6492
|
+
}
|
|
6493
|
+
case "get_scheduled_jobs": {
|
|
6494
|
+
const scheduler = this.getSchedulerAdapter();
|
|
6495
|
+
this.reply(request.id, scheduler ? scheduler.listJobs() : []);
|
|
6496
|
+
return;
|
|
6497
|
+
}
|
|
6498
|
+
case "add_scheduled_job": {
|
|
6499
|
+
const scheduler = this.getSchedulerAdapter();
|
|
6500
|
+
if (!scheduler) {
|
|
6501
|
+
this.replyError(request.id, "Scheduler adapter is not available");
|
|
6502
|
+
return;
|
|
6503
|
+
}
|
|
6504
|
+
const result = scheduler.addJob(request.job);
|
|
6505
|
+
if (!result.success) {
|
|
6506
|
+
this.replyError(request.id, result.message);
|
|
6507
|
+
return;
|
|
6508
|
+
}
|
|
6509
|
+
this.reply(request.id, result);
|
|
6510
|
+
return;
|
|
6511
|
+
}
|
|
6512
|
+
case "remove_scheduled_job": {
|
|
6513
|
+
const scheduler = this.getSchedulerAdapter();
|
|
6514
|
+
if (!scheduler) {
|
|
6515
|
+
this.replyError(request.id, "Scheduler adapter is not available");
|
|
6516
|
+
return;
|
|
6517
|
+
}
|
|
6518
|
+
const result = scheduler.removeJob(request.name);
|
|
6519
|
+
if (!result.success) {
|
|
6520
|
+
this.replyError(request.id, result.message);
|
|
6521
|
+
return;
|
|
6522
|
+
}
|
|
6523
|
+
this.reply(request.id, result);
|
|
6524
|
+
return;
|
|
6525
|
+
}
|
|
6526
|
+
}
|
|
6527
|
+
} catch (err) {
|
|
6528
|
+
this.replyError(
|
|
6529
|
+
request.id,
|
|
6530
|
+
err instanceof Error ? err.message : String(err)
|
|
6531
|
+
);
|
|
6532
|
+
}
|
|
6533
|
+
}
|
|
6534
|
+
getSchedulerAdapter() {
|
|
6535
|
+
const adapter = this.adapterMap?.get("scheduler");
|
|
6536
|
+
if (!adapter) return null;
|
|
6537
|
+
return adapter;
|
|
6538
|
+
}
|
|
6539
|
+
detectPlatform(channelId) {
|
|
6540
|
+
if (channelId.startsWith("telegram-")) return "telegram";
|
|
6541
|
+
if (channelId.startsWith("slack-")) return "slack";
|
|
6542
|
+
if (channelId.startsWith("scheduler-")) return "scheduler";
|
|
6543
|
+
return "web";
|
|
6544
|
+
}
|
|
6545
|
+
sendIpc(payload) {
|
|
6546
|
+
if (typeof process.send === "function") {
|
|
6547
|
+
process.send(payload);
|
|
6548
|
+
}
|
|
6549
|
+
}
|
|
6550
|
+
reply(id, data) {
|
|
6551
|
+
this.sendIpc({ id, type: "result", data });
|
|
6552
|
+
}
|
|
6553
|
+
replyError(id, message) {
|
|
6554
|
+
this.sendIpc({ id, type: "error", message });
|
|
6555
|
+
}
|
|
6556
|
+
};
|
|
6557
|
+
|
|
6158
6558
|
// src/runtime/server.ts
|
|
6159
6559
|
init_config();
|
|
6160
6560
|
|
|
@@ -6231,28 +6631,28 @@ var Lifecycle = class {
|
|
|
6231
6631
|
|
|
6232
6632
|
// src/runtime/registry.ts
|
|
6233
6633
|
import crypto from "crypto";
|
|
6234
|
-
import
|
|
6634
|
+
import fs12 from "fs";
|
|
6235
6635
|
import os from "os";
|
|
6236
|
-
import
|
|
6237
|
-
var SKILLPACK_HOME =
|
|
6238
|
-
var LEGACY_REGISTRY_FILE =
|
|
6239
|
-
var REGISTRY_DIR =
|
|
6636
|
+
import path12 from "path";
|
|
6637
|
+
var SKILLPACK_HOME = path12.join(os.homedir(), ".skillpack");
|
|
6638
|
+
var LEGACY_REGISTRY_FILE = path12.join(SKILLPACK_HOME, "registry.json");
|
|
6639
|
+
var REGISTRY_DIR = path12.join(SKILLPACK_HOME, "registry.d");
|
|
6240
6640
|
var migrationChecked = false;
|
|
6241
6641
|
function ensureHomeDir() {
|
|
6242
|
-
if (!
|
|
6243
|
-
|
|
6642
|
+
if (!fs12.existsSync(SKILLPACK_HOME)) {
|
|
6643
|
+
fs12.mkdirSync(SKILLPACK_HOME, { recursive: true });
|
|
6244
6644
|
}
|
|
6245
6645
|
}
|
|
6246
6646
|
function ensureRegistryDir() {
|
|
6247
6647
|
ensureHomeDir();
|
|
6248
|
-
if (!
|
|
6249
|
-
|
|
6648
|
+
if (!fs12.existsSync(REGISTRY_DIR)) {
|
|
6649
|
+
fs12.mkdirSync(REGISTRY_DIR, { recursive: true });
|
|
6250
6650
|
}
|
|
6251
6651
|
}
|
|
6252
6652
|
function canonicalizeDir(dir) {
|
|
6253
|
-
const resolved =
|
|
6653
|
+
const resolved = path12.resolve(dir);
|
|
6254
6654
|
try {
|
|
6255
|
-
return
|
|
6655
|
+
return fs12.realpathSync(resolved);
|
|
6256
6656
|
} catch {
|
|
6257
6657
|
return resolved;
|
|
6258
6658
|
}
|
|
@@ -6261,7 +6661,7 @@ function hashDir(dir) {
|
|
|
6261
6661
|
return crypto.createHash("md5").update(canonicalizeDir(dir)).digest("hex");
|
|
6262
6662
|
}
|
|
6263
6663
|
function getEntryPathForCanonicalDir(dir) {
|
|
6264
|
-
return
|
|
6664
|
+
return path12.join(REGISTRY_DIR, `${hashDir(dir)}.json`);
|
|
6265
6665
|
}
|
|
6266
6666
|
function getEntryPath(dir) {
|
|
6267
6667
|
ensureRegistryReady();
|
|
@@ -6269,11 +6669,11 @@ function getEntryPath(dir) {
|
|
|
6269
6669
|
}
|
|
6270
6670
|
function listEntryFiles() {
|
|
6271
6671
|
ensureRegistryReady();
|
|
6272
|
-
return
|
|
6672
|
+
return fs12.readdirSync(REGISTRY_DIR).filter((file) => file.endsWith(".json")).sort().map((file) => path12.join(REGISTRY_DIR, file));
|
|
6273
6673
|
}
|
|
6274
6674
|
function readEntryFile(filePath) {
|
|
6275
6675
|
try {
|
|
6276
|
-
const raw =
|
|
6676
|
+
const raw = fs12.readFileSync(filePath, "utf-8");
|
|
6277
6677
|
const data = JSON.parse(raw);
|
|
6278
6678
|
if (typeof data?.dir !== "string" || typeof data?.name !== "string" || typeof data?.version !== "string" || typeof data?.port !== "number" || typeof data?.pid !== "number" && data?.pid !== null || data?.status !== "running" && data?.status !== "stopped") {
|
|
6279
6679
|
return null;
|
|
@@ -6306,8 +6706,8 @@ function writeEntryFile(entry) {
|
|
|
6306
6706
|
};
|
|
6307
6707
|
const entryPath = getEntryPathForCanonicalDir(normalized.dir);
|
|
6308
6708
|
const tmpPath = createTmpPath(entryPath);
|
|
6309
|
-
|
|
6310
|
-
|
|
6709
|
+
fs12.writeFileSync(tmpPath, JSON.stringify(normalized, null, 2), "utf-8");
|
|
6710
|
+
fs12.renameSync(tmpPath, entryPath);
|
|
6311
6711
|
}
|
|
6312
6712
|
function migrateLegacyRegistryIfNeeded() {
|
|
6313
6713
|
if (migrationChecked) {
|
|
@@ -6315,14 +6715,14 @@ function migrateLegacyRegistryIfNeeded() {
|
|
|
6315
6715
|
}
|
|
6316
6716
|
migrationChecked = true;
|
|
6317
6717
|
ensureRegistryDir();
|
|
6318
|
-
if (!
|
|
6718
|
+
if (!fs12.existsSync(LEGACY_REGISTRY_FILE)) {
|
|
6319
6719
|
return;
|
|
6320
6720
|
}
|
|
6321
6721
|
if (listEntryFiles().length > 0) {
|
|
6322
6722
|
return;
|
|
6323
6723
|
}
|
|
6324
6724
|
try {
|
|
6325
|
-
const raw =
|
|
6725
|
+
const raw = fs12.readFileSync(LEGACY_REGISTRY_FILE, "utf-8");
|
|
6326
6726
|
const data = JSON.parse(raw);
|
|
6327
6727
|
const packs = Array.isArray(data?.packs) ? data.packs : [];
|
|
6328
6728
|
for (const pack of packs) {
|
|
@@ -6335,7 +6735,7 @@ function migrateLegacyRegistryIfNeeded() {
|
|
|
6335
6735
|
} catch {
|
|
6336
6736
|
}
|
|
6337
6737
|
}
|
|
6338
|
-
|
|
6738
|
+
fs12.renameSync(LEGACY_REGISTRY_FILE, `${LEGACY_REGISTRY_FILE}.legacy`);
|
|
6339
6739
|
} catch (err) {
|
|
6340
6740
|
console.warn(" [Registry] Failed to migrate legacy registry.json:", err);
|
|
6341
6741
|
}
|
|
@@ -6388,7 +6788,7 @@ function deregister(dir, pid) {
|
|
|
6388
6788
|
}
|
|
6389
6789
|
|
|
6390
6790
|
// src/runtime/server.ts
|
|
6391
|
-
var __dirname =
|
|
6791
|
+
var __dirname = path14.dirname(fileURLToPath2(import.meta.url));
|
|
6392
6792
|
async function startServer(options) {
|
|
6393
6793
|
const {
|
|
6394
6794
|
rootDir,
|
|
@@ -6403,8 +6803,8 @@ async function startServer(options) {
|
|
|
6403
6803
|
const packConfig = loadConfig(canonicalRootDir);
|
|
6404
6804
|
const baseUrl = dataConfig.baseUrl?.trim() || void 0;
|
|
6405
6805
|
const modelId = SUPPORTED_PROVIDERS[provider]?.defaultModelId ?? SUPPORTED_PROVIDERS.openai.defaultModelId;
|
|
6406
|
-
const packageRoot =
|
|
6407
|
-
const webDir =
|
|
6806
|
+
const packageRoot = path14.resolve(__dirname, "..");
|
|
6807
|
+
const webDir = fs15.existsSync(path14.join(rootDir, "web")) ? path14.join(rootDir, "web") : path14.join(packageRoot, "web");
|
|
6408
6808
|
const app = express();
|
|
6409
6809
|
app.use(express.json());
|
|
6410
6810
|
app.use(express.static(webDir));
|
|
@@ -6432,8 +6832,31 @@ async function startServer(options) {
|
|
|
6432
6832
|
});
|
|
6433
6833
|
const adapters = [];
|
|
6434
6834
|
const adapterMap = /* @__PURE__ */ new Map();
|
|
6835
|
+
const hasIpcChannel = typeof process.send === "function";
|
|
6836
|
+
const ipcAdapter = new IpcAdapter();
|
|
6837
|
+
if (hasIpcChannel) {
|
|
6838
|
+
await ipcAdapter.start({
|
|
6839
|
+
agent,
|
|
6840
|
+
server,
|
|
6841
|
+
app,
|
|
6842
|
+
rootDir,
|
|
6843
|
+
lifecycle,
|
|
6844
|
+
adapterMap
|
|
6845
|
+
});
|
|
6846
|
+
adapters.push(ipcAdapter);
|
|
6847
|
+
adapterMap.set(ipcAdapter.name, ipcAdapter);
|
|
6848
|
+
}
|
|
6849
|
+
const ipcBroadcaster = hasIpcChannel ? ipcAdapter : void 0;
|
|
6435
6850
|
const webAdapter = new WebAdapter();
|
|
6436
|
-
await webAdapter.start({
|
|
6851
|
+
await webAdapter.start({
|
|
6852
|
+
agent,
|
|
6853
|
+
server,
|
|
6854
|
+
app,
|
|
6855
|
+
rootDir,
|
|
6856
|
+
lifecycle,
|
|
6857
|
+
adapterMap,
|
|
6858
|
+
ipcBroadcaster
|
|
6859
|
+
});
|
|
6437
6860
|
adapters.push(webAdapter);
|
|
6438
6861
|
adapterMap.set(webAdapter.name, webAdapter);
|
|
6439
6862
|
if (dataConfig.adapters?.telegram?.token) {
|
|
@@ -6442,7 +6865,15 @@ async function startServer(options) {
|
|
|
6442
6865
|
const telegramAdapter = new TelegramAdapter2({
|
|
6443
6866
|
token: dataConfig.adapters.telegram.token
|
|
6444
6867
|
});
|
|
6445
|
-
await telegramAdapter.start({
|
|
6868
|
+
await telegramAdapter.start({
|
|
6869
|
+
agent,
|
|
6870
|
+
server,
|
|
6871
|
+
app,
|
|
6872
|
+
rootDir,
|
|
6873
|
+
lifecycle,
|
|
6874
|
+
adapterMap,
|
|
6875
|
+
ipcBroadcaster
|
|
6876
|
+
});
|
|
6446
6877
|
adapters.push(telegramAdapter);
|
|
6447
6878
|
adapterMap.set(telegramAdapter.name, telegramAdapter);
|
|
6448
6879
|
} catch (err) {
|
|
@@ -6462,7 +6893,15 @@ async function startServer(options) {
|
|
|
6462
6893
|
botToken: slackConfig.botToken,
|
|
6463
6894
|
appToken: slackConfig.appToken
|
|
6464
6895
|
});
|
|
6465
|
-
await slackAdapter.start({
|
|
6896
|
+
await slackAdapter.start({
|
|
6897
|
+
agent,
|
|
6898
|
+
server,
|
|
6899
|
+
app,
|
|
6900
|
+
rootDir,
|
|
6901
|
+
lifecycle,
|
|
6902
|
+
adapterMap,
|
|
6903
|
+
ipcBroadcaster
|
|
6904
|
+
});
|
|
6466
6905
|
adapters.push(slackAdapter);
|
|
6467
6906
|
adapterMap.set(slackAdapter.name, slackAdapter);
|
|
6468
6907
|
} catch (err) {
|
|
@@ -6525,6 +6964,9 @@ async function startServer(options) {
|
|
|
6525
6964
|
} catch (err) {
|
|
6526
6965
|
console.warn(" [Registry] Could not register pack:", err);
|
|
6527
6966
|
}
|
|
6967
|
+
if (hasIpcChannel) {
|
|
6968
|
+
ipcAdapter.notifyReady(typeof actualPort === "number" ? actualPort : port);
|
|
6969
|
+
}
|
|
6528
6970
|
if (!daemonRun) {
|
|
6529
6971
|
const cmd = process.platform === "darwin" ? `open ${url}` : process.platform === "win32" ? `start ${url}` : `xdg-open ${url}`;
|
|
6530
6972
|
exec(cmd, (err) => {
|
|
@@ -6572,23 +7014,23 @@ function findMissingSkills(workDir, config) {
|
|
|
6572
7014
|
});
|
|
6573
7015
|
}
|
|
6574
7016
|
function copyStartTemplates2(workDir) {
|
|
6575
|
-
const templateDir =
|
|
7017
|
+
const templateDir = path15.resolve(
|
|
6576
7018
|
new URL("../templates", import.meta.url).pathname
|
|
6577
7019
|
);
|
|
6578
7020
|
for (const file of ["start.sh", "start.bat"]) {
|
|
6579
|
-
const src =
|
|
6580
|
-
const dest =
|
|
6581
|
-
if (
|
|
6582
|
-
|
|
7021
|
+
const src = path15.join(templateDir, file);
|
|
7022
|
+
const dest = path15.join(workDir, file);
|
|
7023
|
+
if (fs16.existsSync(src)) {
|
|
7024
|
+
fs16.copyFileSync(src, dest);
|
|
6583
7025
|
if (file === "start.sh") {
|
|
6584
|
-
|
|
7026
|
+
fs16.chmodSync(dest, 493);
|
|
6585
7027
|
}
|
|
6586
7028
|
}
|
|
6587
7029
|
}
|
|
6588
7030
|
}
|
|
6589
7031
|
async function runCommand(directory) {
|
|
6590
|
-
const workDir = directory ?
|
|
6591
|
-
|
|
7032
|
+
const workDir = directory ? path15.resolve(directory) : process.cwd();
|
|
7033
|
+
fs16.mkdirSync(workDir, { recursive: true });
|
|
6592
7034
|
if (!configExists(workDir)) {
|
|
6593
7035
|
console.log(chalk4.blue("\n No skillpack.json found. Let's set one up.\n"));
|
|
6594
7036
|
const { name, description } = await inquirer2.prompt([
|
|
@@ -6633,9 +7075,9 @@ async function runCommand(directory) {
|
|
|
6633
7075
|
}
|
|
6634
7076
|
|
|
6635
7077
|
// src/cli.ts
|
|
6636
|
-
import
|
|
7078
|
+
import fs17 from "fs";
|
|
6637
7079
|
var packageJson = JSON.parse(
|
|
6638
|
-
|
|
7080
|
+
fs17.readFileSync(new URL("../package.json", import.meta.url), "utf-8")
|
|
6639
7081
|
);
|
|
6640
7082
|
var program = new Command();
|
|
6641
7083
|
program.name("skillpack").description("Assemble, package, and run Agent Skills packs").version(packageJson.version);
|