@cremini/skillpack 1.2.5-beta.1 → 1.2.5
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 +102 -506
- package/package.json +2 -2
- package/templates/start.bat +1 -1
- package/templates/start.sh +1 -1
- package/web/index.html +13 -0
- package/web/js/api-key-dialog.js +42 -0
package/dist/cli.js
CHANGED
|
@@ -107,6 +107,12 @@ var init_config = __esm({
|
|
|
107
107
|
if (updates.baseUrl !== void 0) {
|
|
108
108
|
this.configData.baseUrl = updates.baseUrl?.trim() || void 0;
|
|
109
109
|
}
|
|
110
|
+
if (updates.modelId !== void 0) {
|
|
111
|
+
this.configData.modelId = updates.modelId?.trim() || void 0;
|
|
112
|
+
}
|
|
113
|
+
if (updates.apiProtocol !== void 0) {
|
|
114
|
+
this.configData.apiProtocol = updates.apiProtocol || void 0;
|
|
115
|
+
}
|
|
110
116
|
if (updates.adapters !== void 0) {
|
|
111
117
|
const merged = { ...this.configData.adapters || {} };
|
|
112
118
|
for (const [adapterKey, adapterVal] of Object.entries(updates.adapters)) {
|
|
@@ -323,20 +329,6 @@ var init_commands = __esm({
|
|
|
323
329
|
}
|
|
324
330
|
});
|
|
325
331
|
|
|
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
|
-
|
|
340
332
|
// src/runtime/adapters/markdown.ts
|
|
341
333
|
function unwrapMarkdownSourceBlocks(text) {
|
|
342
334
|
return text.replace(
|
|
@@ -457,7 +449,7 @@ var telegram_exports = {};
|
|
|
457
449
|
__export(telegram_exports, {
|
|
458
450
|
TelegramAdapter: () => TelegramAdapter
|
|
459
451
|
});
|
|
460
|
-
import
|
|
452
|
+
import fs12 from "fs";
|
|
461
453
|
import TelegramBot from "node-telegram-bot-api";
|
|
462
454
|
var MAX_MESSAGE_LENGTH, ACK_REACTION, TelegramAdapter;
|
|
463
455
|
var init_telegram = __esm({
|
|
@@ -477,14 +469,12 @@ var init_telegram = __esm({
|
|
|
477
469
|
agent = null;
|
|
478
470
|
options;
|
|
479
471
|
rootDir = "";
|
|
480
|
-
ipcBroadcaster = null;
|
|
481
472
|
constructor(options) {
|
|
482
473
|
this.options = options;
|
|
483
474
|
}
|
|
484
475
|
async start(ctx) {
|
|
485
476
|
this.agent = ctx.agent;
|
|
486
477
|
this.rootDir = ctx.rootDir;
|
|
487
|
-
this.ipcBroadcaster = ctx.ipcBroadcaster ?? null;
|
|
488
478
|
this.bot = new TelegramBot(this.options.token, { polling: true });
|
|
489
479
|
this.bot.on("message", (msg) => {
|
|
490
480
|
this.handleTelegramMessage(msg).catch((err) => {
|
|
@@ -526,15 +516,6 @@ var init_telegram = __esm({
|
|
|
526
516
|
const messageId = msg.message_id;
|
|
527
517
|
const text = (msg.text || msg.caption || "").trim();
|
|
528
518
|
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
|
-
);
|
|
538
519
|
const attachments = await this.extractAttachments(msg, channelId);
|
|
539
520
|
if (!text && attachments.length === 0) return;
|
|
540
521
|
await this.tryAckReaction(chatId, messageId);
|
|
@@ -564,7 +545,6 @@ var init_telegram = __esm({
|
|
|
564
545
|
});
|
|
565
546
|
break;
|
|
566
547
|
}
|
|
567
|
-
this.ipcBroadcaster?.broadcastAgentEvent(channelId, event);
|
|
568
548
|
};
|
|
569
549
|
try {
|
|
570
550
|
const userText = text || "(User sent an attachment)";
|
|
@@ -775,7 +755,7 @@ var init_telegram = __esm({
|
|
|
775
755
|
async sendFileSafe(chatId, filePath, caption) {
|
|
776
756
|
if (!this.bot) return;
|
|
777
757
|
try {
|
|
778
|
-
if (!
|
|
758
|
+
if (!fs12.existsSync(filePath)) {
|
|
779
759
|
console.error(`[Telegram] File not found for sending: ${filePath}`);
|
|
780
760
|
return;
|
|
781
761
|
}
|
|
@@ -795,8 +775,8 @@ var slack_exports = {};
|
|
|
795
775
|
__export(slack_exports, {
|
|
796
776
|
SlackAdapter: () => SlackAdapter
|
|
797
777
|
});
|
|
798
|
-
import
|
|
799
|
-
import
|
|
778
|
+
import fs13 from "fs";
|
|
779
|
+
import path12 from "path";
|
|
800
780
|
import { App, LogLevel } from "@slack/bolt";
|
|
801
781
|
var INLINE_COMMANDS, SLASH_COMMANDS, MAX_MESSAGE_LENGTH2, ACK_REACTION2, PROCESSING_MESSAGE, SlackAdapter;
|
|
802
782
|
var init_slack = __esm({
|
|
@@ -827,14 +807,12 @@ var init_slack = __esm({
|
|
|
827
807
|
botUserId = null;
|
|
828
808
|
lastThreadByChannel = /* @__PURE__ */ new Map();
|
|
829
809
|
rootDir = "";
|
|
830
|
-
ipcBroadcaster = null;
|
|
831
810
|
constructor(options) {
|
|
832
811
|
this.options = options;
|
|
833
812
|
}
|
|
834
813
|
async start(ctx) {
|
|
835
814
|
this.agent = ctx.agent;
|
|
836
815
|
this.rootDir = ctx.rootDir;
|
|
837
|
-
this.ipcBroadcaster = ctx.ipcBroadcaster ?? null;
|
|
838
816
|
this.app = new App({
|
|
839
817
|
token: this.options.botToken,
|
|
840
818
|
appToken: this.options.appToken,
|
|
@@ -920,15 +898,6 @@ var init_slack = __esm({
|
|
|
920
898
|
const teamId = this.getTeamId(body, context);
|
|
921
899
|
const channelId = `slack-dm-${teamId}-${event.channel}`;
|
|
922
900
|
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
|
-
);
|
|
932
901
|
const attachments = await this.extractSlackFiles(event, channelId, client);
|
|
933
902
|
if (!text && attachments.length === 0) return;
|
|
934
903
|
await this.tryAckReaction(client, event);
|
|
@@ -959,15 +928,6 @@ var init_slack = __esm({
|
|
|
959
928
|
threadTs
|
|
960
929
|
);
|
|
961
930
|
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
|
-
);
|
|
971
931
|
const attachments = await this.extractSlackFiles(event, channelId, client);
|
|
972
932
|
if (!text && attachments.length === 0) {
|
|
973
933
|
await this.sendSafe(
|
|
@@ -1027,7 +987,6 @@ var init_slack = __esm({
|
|
|
1027
987
|
caption: event.caption
|
|
1028
988
|
});
|
|
1029
989
|
}
|
|
1030
|
-
this.ipcBroadcaster?.broadcastAgentEvent(channelId, event);
|
|
1031
990
|
};
|
|
1032
991
|
try {
|
|
1033
992
|
const result = await this.agent.handleMessage(
|
|
@@ -1431,12 +1390,12 @@ var init_slack = __esm({
|
|
|
1431
1390
|
*/
|
|
1432
1391
|
async sendFileSafe(client, route, filePath, caption) {
|
|
1433
1392
|
try {
|
|
1434
|
-
if (!
|
|
1393
|
+
if (!fs13.existsSync(filePath)) {
|
|
1435
1394
|
console.error(`[Slack] File not found for sending: ${filePath}`);
|
|
1436
1395
|
return;
|
|
1437
1396
|
}
|
|
1438
|
-
const filename =
|
|
1439
|
-
const fileContent =
|
|
1397
|
+
const filename = path12.basename(filePath);
|
|
1398
|
+
const fileContent = fs13.readFileSync(filePath);
|
|
1440
1399
|
await client.files.uploadV2({
|
|
1441
1400
|
channel_id: route.channel,
|
|
1442
1401
|
thread_ts: route.threadTs,
|
|
@@ -1453,6 +1412,20 @@ var init_slack = __esm({
|
|
|
1453
1412
|
}
|
|
1454
1413
|
});
|
|
1455
1414
|
|
|
1415
|
+
// src/runtime/adapters/types.ts
|
|
1416
|
+
var types_exports = {};
|
|
1417
|
+
__export(types_exports, {
|
|
1418
|
+
isMessageSender: () => isMessageSender
|
|
1419
|
+
});
|
|
1420
|
+
function isMessageSender(adapter) {
|
|
1421
|
+
return typeof adapter.sendMessage === "function";
|
|
1422
|
+
}
|
|
1423
|
+
var init_types = __esm({
|
|
1424
|
+
"src/runtime/adapters/types.ts"() {
|
|
1425
|
+
"use strict";
|
|
1426
|
+
}
|
|
1427
|
+
});
|
|
1428
|
+
|
|
1456
1429
|
// src/runtime/adapters/scheduler.ts
|
|
1457
1430
|
var scheduler_exports = {};
|
|
1458
1431
|
__export(scheduler_exports, {
|
|
@@ -2463,15 +2436,15 @@ async function interactiveCreate(workDir) {
|
|
|
2463
2436
|
}
|
|
2464
2437
|
|
|
2465
2438
|
// src/commands/run.ts
|
|
2466
|
-
import
|
|
2467
|
-
import
|
|
2439
|
+
import path14 from "path";
|
|
2440
|
+
import fs15 from "fs";
|
|
2468
2441
|
import inquirer2 from "inquirer";
|
|
2469
2442
|
import chalk4 from "chalk";
|
|
2470
2443
|
|
|
2471
2444
|
// src/runtime/server.ts
|
|
2472
2445
|
import express from "express";
|
|
2473
|
-
import
|
|
2474
|
-
import
|
|
2446
|
+
import path13 from "path";
|
|
2447
|
+
import fs14 from "fs";
|
|
2475
2448
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2476
2449
|
import { createServer } from "http";
|
|
2477
2450
|
import { exec } from "child_process";
|
|
@@ -5598,10 +5571,30 @@ var PackAgent = class {
|
|
|
5598
5571
|
const { rootDir, provider, modelId, baseUrl } = this.options;
|
|
5599
5572
|
const authStorage = this.authStorage;
|
|
5600
5573
|
const modelRegistry = new ModelRegistry(authStorage);
|
|
5574
|
+
if (baseUrl && modelId) {
|
|
5575
|
+
const apiProtocol = this.options.apiProtocol ?? "openai-completions";
|
|
5576
|
+
log(`[PackAgent] Registering custom model ${provider}/${modelId} api=${apiProtocol} baseUrl=${baseUrl}`);
|
|
5577
|
+
modelRegistry.registerProvider(provider, {
|
|
5578
|
+
baseUrl,
|
|
5579
|
+
apiKey: this.options.apiKey,
|
|
5580
|
+
models: [
|
|
5581
|
+
{
|
|
5582
|
+
id: modelId,
|
|
5583
|
+
name: modelId,
|
|
5584
|
+
api: apiProtocol,
|
|
5585
|
+
reasoning: false,
|
|
5586
|
+
input: ["text"],
|
|
5587
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
5588
|
+
contextWindow: 128e3,
|
|
5589
|
+
maxTokens: 4096
|
|
5590
|
+
}
|
|
5591
|
+
]
|
|
5592
|
+
});
|
|
5593
|
+
}
|
|
5601
5594
|
const resolvedModel = modelRegistry.find(provider, modelId);
|
|
5602
|
-
const model = resolvedModel && baseUrl ? { ...resolvedModel, baseUrl } : resolvedModel;
|
|
5595
|
+
const model = resolvedModel && baseUrl && !this.options.apiProtocol ? { ...resolvedModel, baseUrl } : resolvedModel;
|
|
5603
5596
|
if (resolvedModel && baseUrl) {
|
|
5604
|
-
log(`[PackAgent]
|
|
5597
|
+
log(`[PackAgent] Resolved ${provider}/${modelId} api=${resolvedModel.api} baseUrl=${baseUrl}`);
|
|
5605
5598
|
}
|
|
5606
5599
|
const sessionDir = path9.resolve(
|
|
5607
5600
|
rootDir,
|
|
@@ -5868,9 +5861,6 @@ ${text}`;
|
|
|
5868
5861
|
/** Reserved: restore a historical session */
|
|
5869
5862
|
async restoreSession(_sessionId) {
|
|
5870
5863
|
}
|
|
5871
|
-
getActiveChannelIds() {
|
|
5872
|
-
return Array.from(this.channels.keys());
|
|
5873
|
-
}
|
|
5874
5864
|
};
|
|
5875
5865
|
|
|
5876
5866
|
// src/runtime/adapters/web.ts
|
|
@@ -5895,6 +5885,8 @@ function getRuntimeConfigSignature(config) {
|
|
|
5895
5885
|
apiKey: config.apiKey || "",
|
|
5896
5886
|
provider: config.provider || "openai",
|
|
5897
5887
|
baseUrl: config.baseUrl || "",
|
|
5888
|
+
modelId: config.modelId || "",
|
|
5889
|
+
apiProtocol: config.apiProtocol || "",
|
|
5898
5890
|
telegramToken: config.adapters?.telegram?.token || "",
|
|
5899
5891
|
slackBotToken: config.adapters?.slack?.botToken || "",
|
|
5900
5892
|
slackAppToken: config.adapters?.slack?.appToken || ""
|
|
@@ -5904,11 +5896,9 @@ var WebAdapter = class {
|
|
|
5904
5896
|
name = "web";
|
|
5905
5897
|
wss = null;
|
|
5906
5898
|
agent = null;
|
|
5907
|
-
ipcBroadcaster = null;
|
|
5908
5899
|
async start(ctx) {
|
|
5909
5900
|
const { agent, server, app, rootDir, lifecycle } = ctx;
|
|
5910
5901
|
this.agent = agent;
|
|
5911
|
-
this.ipcBroadcaster = ctx.ipcBroadcaster ?? null;
|
|
5912
5902
|
const currentConf = configManager.getConfig();
|
|
5913
5903
|
let apiKey = currentConf.apiKey || "";
|
|
5914
5904
|
let currentProvider = currentConf.provider || "openai";
|
|
@@ -5927,6 +5917,8 @@ var WebAdapter = class {
|
|
|
5927
5917
|
apiKey: conf.apiKey || "",
|
|
5928
5918
|
provider: currentProvider2,
|
|
5929
5919
|
baseUrl: conf.baseUrl || "",
|
|
5920
|
+
modelId: conf.modelId || "",
|
|
5921
|
+
apiProtocol: conf.apiProtocol || "",
|
|
5930
5922
|
adapters: conf.adapters || {},
|
|
5931
5923
|
supportedProviders: SUPPORTED_PROVIDERS,
|
|
5932
5924
|
oauthConnected
|
|
@@ -5937,7 +5929,7 @@ var WebAdapter = class {
|
|
|
5937
5929
|
res.json(config.skills || []);
|
|
5938
5930
|
});
|
|
5939
5931
|
app.post("/api/config/update", (req, res) => {
|
|
5940
|
-
const { key, provider, baseUrl, adapters } = req.body;
|
|
5932
|
+
const { key, provider, baseUrl, modelId, apiProtocol, adapters } = req.body;
|
|
5941
5933
|
const updates = {};
|
|
5942
5934
|
const beforeConfig = JSON.parse(JSON.stringify(configManager.getConfig()));
|
|
5943
5935
|
if (key !== void 0) {
|
|
@@ -5951,6 +5943,12 @@ var WebAdapter = class {
|
|
|
5951
5943
|
if (baseUrl !== void 0) {
|
|
5952
5944
|
updates.baseUrl = baseUrl;
|
|
5953
5945
|
}
|
|
5946
|
+
if (modelId !== void 0) {
|
|
5947
|
+
updates.modelId = modelId;
|
|
5948
|
+
}
|
|
5949
|
+
if (apiProtocol !== void 0) {
|
|
5950
|
+
updates.apiProtocol = apiProtocol;
|
|
5951
|
+
}
|
|
5954
5952
|
if (adapters !== void 0) {
|
|
5955
5953
|
updates.adapters = adapters;
|
|
5956
5954
|
}
|
|
@@ -6176,7 +6174,6 @@ var WebAdapter = class {
|
|
|
6176
6174
|
}
|
|
6177
6175
|
const onEvent = (event) => {
|
|
6178
6176
|
sendWsEvent(ws, event);
|
|
6179
|
-
this.ipcBroadcaster?.broadcastAgentEvent(channelId, event);
|
|
6180
6177
|
};
|
|
6181
6178
|
const result = await agent.handleMessage("web", channelId, text, onEvent);
|
|
6182
6179
|
if (result.errorMessage) {
|
|
@@ -6194,367 +6191,6 @@ var WebAdapter = class {
|
|
|
6194
6191
|
}
|
|
6195
6192
|
};
|
|
6196
6193
|
|
|
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
|
-
|
|
6558
6194
|
// src/runtime/server.ts
|
|
6559
6195
|
init_config();
|
|
6560
6196
|
|
|
@@ -6631,28 +6267,28 @@ var Lifecycle = class {
|
|
|
6631
6267
|
|
|
6632
6268
|
// src/runtime/registry.ts
|
|
6633
6269
|
import crypto from "crypto";
|
|
6634
|
-
import
|
|
6270
|
+
import fs11 from "fs";
|
|
6635
6271
|
import os from "os";
|
|
6636
|
-
import
|
|
6637
|
-
var SKILLPACK_HOME =
|
|
6638
|
-
var LEGACY_REGISTRY_FILE =
|
|
6639
|
-
var REGISTRY_DIR =
|
|
6272
|
+
import path11 from "path";
|
|
6273
|
+
var SKILLPACK_HOME = path11.join(os.homedir(), ".skillpack");
|
|
6274
|
+
var LEGACY_REGISTRY_FILE = path11.join(SKILLPACK_HOME, "registry.json");
|
|
6275
|
+
var REGISTRY_DIR = path11.join(SKILLPACK_HOME, "registry.d");
|
|
6640
6276
|
var migrationChecked = false;
|
|
6641
6277
|
function ensureHomeDir() {
|
|
6642
|
-
if (!
|
|
6643
|
-
|
|
6278
|
+
if (!fs11.existsSync(SKILLPACK_HOME)) {
|
|
6279
|
+
fs11.mkdirSync(SKILLPACK_HOME, { recursive: true });
|
|
6644
6280
|
}
|
|
6645
6281
|
}
|
|
6646
6282
|
function ensureRegistryDir() {
|
|
6647
6283
|
ensureHomeDir();
|
|
6648
|
-
if (!
|
|
6649
|
-
|
|
6284
|
+
if (!fs11.existsSync(REGISTRY_DIR)) {
|
|
6285
|
+
fs11.mkdirSync(REGISTRY_DIR, { recursive: true });
|
|
6650
6286
|
}
|
|
6651
6287
|
}
|
|
6652
6288
|
function canonicalizeDir(dir) {
|
|
6653
|
-
const resolved =
|
|
6289
|
+
const resolved = path11.resolve(dir);
|
|
6654
6290
|
try {
|
|
6655
|
-
return
|
|
6291
|
+
return fs11.realpathSync(resolved);
|
|
6656
6292
|
} catch {
|
|
6657
6293
|
return resolved;
|
|
6658
6294
|
}
|
|
@@ -6661,7 +6297,7 @@ function hashDir(dir) {
|
|
|
6661
6297
|
return crypto.createHash("md5").update(canonicalizeDir(dir)).digest("hex");
|
|
6662
6298
|
}
|
|
6663
6299
|
function getEntryPathForCanonicalDir(dir) {
|
|
6664
|
-
return
|
|
6300
|
+
return path11.join(REGISTRY_DIR, `${hashDir(dir)}.json`);
|
|
6665
6301
|
}
|
|
6666
6302
|
function getEntryPath(dir) {
|
|
6667
6303
|
ensureRegistryReady();
|
|
@@ -6669,11 +6305,11 @@ function getEntryPath(dir) {
|
|
|
6669
6305
|
}
|
|
6670
6306
|
function listEntryFiles() {
|
|
6671
6307
|
ensureRegistryReady();
|
|
6672
|
-
return
|
|
6308
|
+
return fs11.readdirSync(REGISTRY_DIR).filter((file) => file.endsWith(".json")).sort().map((file) => path11.join(REGISTRY_DIR, file));
|
|
6673
6309
|
}
|
|
6674
6310
|
function readEntryFile(filePath) {
|
|
6675
6311
|
try {
|
|
6676
|
-
const raw =
|
|
6312
|
+
const raw = fs11.readFileSync(filePath, "utf-8");
|
|
6677
6313
|
const data = JSON.parse(raw);
|
|
6678
6314
|
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") {
|
|
6679
6315
|
return null;
|
|
@@ -6706,8 +6342,8 @@ function writeEntryFile(entry) {
|
|
|
6706
6342
|
};
|
|
6707
6343
|
const entryPath = getEntryPathForCanonicalDir(normalized.dir);
|
|
6708
6344
|
const tmpPath = createTmpPath(entryPath);
|
|
6709
|
-
|
|
6710
|
-
|
|
6345
|
+
fs11.writeFileSync(tmpPath, JSON.stringify(normalized, null, 2), "utf-8");
|
|
6346
|
+
fs11.renameSync(tmpPath, entryPath);
|
|
6711
6347
|
}
|
|
6712
6348
|
function migrateLegacyRegistryIfNeeded() {
|
|
6713
6349
|
if (migrationChecked) {
|
|
@@ -6715,14 +6351,14 @@ function migrateLegacyRegistryIfNeeded() {
|
|
|
6715
6351
|
}
|
|
6716
6352
|
migrationChecked = true;
|
|
6717
6353
|
ensureRegistryDir();
|
|
6718
|
-
if (!
|
|
6354
|
+
if (!fs11.existsSync(LEGACY_REGISTRY_FILE)) {
|
|
6719
6355
|
return;
|
|
6720
6356
|
}
|
|
6721
6357
|
if (listEntryFiles().length > 0) {
|
|
6722
6358
|
return;
|
|
6723
6359
|
}
|
|
6724
6360
|
try {
|
|
6725
|
-
const raw =
|
|
6361
|
+
const raw = fs11.readFileSync(LEGACY_REGISTRY_FILE, "utf-8");
|
|
6726
6362
|
const data = JSON.parse(raw);
|
|
6727
6363
|
const packs = Array.isArray(data?.packs) ? data.packs : [];
|
|
6728
6364
|
for (const pack of packs) {
|
|
@@ -6735,7 +6371,7 @@ function migrateLegacyRegistryIfNeeded() {
|
|
|
6735
6371
|
} catch {
|
|
6736
6372
|
}
|
|
6737
6373
|
}
|
|
6738
|
-
|
|
6374
|
+
fs11.renameSync(LEGACY_REGISTRY_FILE, `${LEGACY_REGISTRY_FILE}.legacy`);
|
|
6739
6375
|
} catch (err) {
|
|
6740
6376
|
console.warn(" [Registry] Failed to migrate legacy registry.json:", err);
|
|
6741
6377
|
}
|
|
@@ -6788,7 +6424,7 @@ function deregister(dir, pid) {
|
|
|
6788
6424
|
}
|
|
6789
6425
|
|
|
6790
6426
|
// src/runtime/server.ts
|
|
6791
|
-
var __dirname =
|
|
6427
|
+
var __dirname = path13.dirname(fileURLToPath2(import.meta.url));
|
|
6792
6428
|
async function startServer(options) {
|
|
6793
6429
|
const {
|
|
6794
6430
|
rootDir,
|
|
@@ -6802,9 +6438,10 @@ async function startServer(options) {
|
|
|
6802
6438
|
const canonicalRootDir = canonicalizeDir(rootDir);
|
|
6803
6439
|
const packConfig = loadConfig(canonicalRootDir);
|
|
6804
6440
|
const baseUrl = dataConfig.baseUrl?.trim() || void 0;
|
|
6805
|
-
const modelId = SUPPORTED_PROVIDERS[provider]?.defaultModelId ?? SUPPORTED_PROVIDERS.openai.defaultModelId;
|
|
6806
|
-
const
|
|
6807
|
-
const
|
|
6441
|
+
const modelId = dataConfig.modelId?.trim() || (SUPPORTED_PROVIDERS[provider]?.defaultModelId ?? SUPPORTED_PROVIDERS.openai.defaultModelId);
|
|
6442
|
+
const apiProtocol = dataConfig.apiProtocol;
|
|
6443
|
+
const packageRoot = path13.resolve(__dirname, "..");
|
|
6444
|
+
const webDir = fs14.existsSync(path13.join(rootDir, "web")) ? path13.join(rootDir, "web") : path13.join(packageRoot, "web");
|
|
6808
6445
|
const app = express();
|
|
6809
6446
|
app.use(express.json());
|
|
6810
6447
|
app.use(express.static(webDir));
|
|
@@ -6828,35 +6465,13 @@ async function startServer(options) {
|
|
|
6828
6465
|
provider,
|
|
6829
6466
|
modelId,
|
|
6830
6467
|
baseUrl,
|
|
6468
|
+
apiProtocol,
|
|
6831
6469
|
lifecycleHandler: lifecycle
|
|
6832
6470
|
});
|
|
6833
6471
|
const adapters = [];
|
|
6834
6472
|
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;
|
|
6850
6473
|
const webAdapter = new WebAdapter();
|
|
6851
|
-
await webAdapter.start({
|
|
6852
|
-
agent,
|
|
6853
|
-
server,
|
|
6854
|
-
app,
|
|
6855
|
-
rootDir,
|
|
6856
|
-
lifecycle,
|
|
6857
|
-
adapterMap,
|
|
6858
|
-
ipcBroadcaster
|
|
6859
|
-
});
|
|
6474
|
+
await webAdapter.start({ agent, server, app, rootDir, lifecycle, adapterMap });
|
|
6860
6475
|
adapters.push(webAdapter);
|
|
6861
6476
|
adapterMap.set(webAdapter.name, webAdapter);
|
|
6862
6477
|
if (dataConfig.adapters?.telegram?.token) {
|
|
@@ -6865,15 +6480,7 @@ async function startServer(options) {
|
|
|
6865
6480
|
const telegramAdapter = new TelegramAdapter2({
|
|
6866
6481
|
token: dataConfig.adapters.telegram.token
|
|
6867
6482
|
});
|
|
6868
|
-
await telegramAdapter.start({
|
|
6869
|
-
agent,
|
|
6870
|
-
server,
|
|
6871
|
-
app,
|
|
6872
|
-
rootDir,
|
|
6873
|
-
lifecycle,
|
|
6874
|
-
adapterMap,
|
|
6875
|
-
ipcBroadcaster
|
|
6876
|
-
});
|
|
6483
|
+
await telegramAdapter.start({ agent, server, app, rootDir, lifecycle });
|
|
6877
6484
|
adapters.push(telegramAdapter);
|
|
6878
6485
|
adapterMap.set(telegramAdapter.name, telegramAdapter);
|
|
6879
6486
|
} catch (err) {
|
|
@@ -6893,15 +6500,7 @@ async function startServer(options) {
|
|
|
6893
6500
|
botToken: slackConfig.botToken,
|
|
6894
6501
|
appToken: slackConfig.appToken
|
|
6895
6502
|
});
|
|
6896
|
-
await slackAdapter.start({
|
|
6897
|
-
agent,
|
|
6898
|
-
server,
|
|
6899
|
-
app,
|
|
6900
|
-
rootDir,
|
|
6901
|
-
lifecycle,
|
|
6902
|
-
adapterMap,
|
|
6903
|
-
ipcBroadcaster
|
|
6904
|
-
});
|
|
6503
|
+
await slackAdapter.start({ agent, server, app, rootDir, lifecycle });
|
|
6905
6504
|
adapters.push(slackAdapter);
|
|
6906
6505
|
adapterMap.set(slackAdapter.name, slackAdapter);
|
|
6907
6506
|
} catch (err) {
|
|
@@ -6964,9 +6563,6 @@ async function startServer(options) {
|
|
|
6964
6563
|
} catch (err) {
|
|
6965
6564
|
console.warn(" [Registry] Could not register pack:", err);
|
|
6966
6565
|
}
|
|
6967
|
-
if (hasIpcChannel) {
|
|
6968
|
-
ipcAdapter.notifyReady(typeof actualPort === "number" ? actualPort : port);
|
|
6969
|
-
}
|
|
6970
6566
|
if (!daemonRun) {
|
|
6971
6567
|
const cmd = process.platform === "darwin" ? `open ${url}` : process.platform === "win32" ? `start ${url}` : `xdg-open ${url}`;
|
|
6972
6568
|
exec(cmd, (err) => {
|
|
@@ -7014,23 +6610,23 @@ function findMissingSkills(workDir, config) {
|
|
|
7014
6610
|
});
|
|
7015
6611
|
}
|
|
7016
6612
|
function copyStartTemplates2(workDir) {
|
|
7017
|
-
const templateDir =
|
|
6613
|
+
const templateDir = path14.resolve(
|
|
7018
6614
|
new URL("../templates", import.meta.url).pathname
|
|
7019
6615
|
);
|
|
7020
6616
|
for (const file of ["start.sh", "start.bat"]) {
|
|
7021
|
-
const src =
|
|
7022
|
-
const dest =
|
|
7023
|
-
if (
|
|
7024
|
-
|
|
6617
|
+
const src = path14.join(templateDir, file);
|
|
6618
|
+
const dest = path14.join(workDir, file);
|
|
6619
|
+
if (fs15.existsSync(src)) {
|
|
6620
|
+
fs15.copyFileSync(src, dest);
|
|
7025
6621
|
if (file === "start.sh") {
|
|
7026
|
-
|
|
6622
|
+
fs15.chmodSync(dest, 493);
|
|
7027
6623
|
}
|
|
7028
6624
|
}
|
|
7029
6625
|
}
|
|
7030
6626
|
}
|
|
7031
6627
|
async function runCommand(directory) {
|
|
7032
|
-
const workDir = directory ?
|
|
7033
|
-
|
|
6628
|
+
const workDir = directory ? path14.resolve(directory) : process.cwd();
|
|
6629
|
+
fs15.mkdirSync(workDir, { recursive: true });
|
|
7034
6630
|
if (!configExists(workDir)) {
|
|
7035
6631
|
console.log(chalk4.blue("\n No skillpack.json found. Let's set one up.\n"));
|
|
7036
6632
|
const { name, description } = await inquirer2.prompt([
|
|
@@ -7075,9 +6671,9 @@ async function runCommand(directory) {
|
|
|
7075
6671
|
}
|
|
7076
6672
|
|
|
7077
6673
|
// src/cli.ts
|
|
7078
|
-
import
|
|
6674
|
+
import fs16 from "fs";
|
|
7079
6675
|
var packageJson = JSON.parse(
|
|
7080
|
-
|
|
6676
|
+
fs16.readFileSync(new URL("../package.json", import.meta.url), "utf-8")
|
|
7081
6677
|
);
|
|
7082
6678
|
var program = new Command();
|
|
7083
6679
|
program.name("skillpack").description("Assemble, package, and run Agent Skills packs").version(packageJson.version);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cremini/skillpack",
|
|
3
|
-
"version": "1.2.5
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "Pack AI Skills into Local Agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -65,4 +65,4 @@
|
|
|
65
65
|
"tsup": "^8.5.1",
|
|
66
66
|
"typescript": "^5.9.3"
|
|
67
67
|
}
|
|
68
|
-
}
|
|
68
|
+
}
|
package/templates/start.bat
CHANGED
package/templates/start.sh
CHANGED
package/web/index.html
CHANGED
|
@@ -96,6 +96,19 @@
|
|
|
96
96
|
<label>Custom Base URL <span class="label-hint">(optional)</span></label>
|
|
97
97
|
<input type="text" id="apikey-baseurl-input" placeholder="https://api.openai.com/v1" class="form-input" />
|
|
98
98
|
</div>
|
|
99
|
+
<div class="form-group" id="apikey-modelid-group" style="display: none;">
|
|
100
|
+
<label>Custom Model Name <span class="label-hint">(optional)</span></label>
|
|
101
|
+
<input type="text" id="apikey-modelid-input" placeholder="e.g. gpt-4o, llama-3-70b" class="form-input" />
|
|
102
|
+
</div>
|
|
103
|
+
<div class="form-group" id="apikey-protocol-group" style="display: none;">
|
|
104
|
+
<label>API Protocol</label>
|
|
105
|
+
<div class="provider-select-wrapper">
|
|
106
|
+
<select id="apikey-protocol-select" class="form-input">
|
|
107
|
+
<option value="openai-completions">Chat Completions API (most proxies)</option>
|
|
108
|
+
<option value="openai-responses">Responses API (native OpenAI)</option>
|
|
109
|
+
</select>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
99
112
|
</div>
|
|
100
113
|
|
|
101
114
|
<!-- OAuth Section -->
|
package/web/js/api-key-dialog.js
CHANGED
|
@@ -16,6 +16,10 @@ let providerSelect;
|
|
|
16
16
|
let apiKeyInput;
|
|
17
17
|
let baseUrlInput;
|
|
18
18
|
let baseUrlGroup;
|
|
19
|
+
let modelIdInput;
|
|
20
|
+
let modelIdGroup;
|
|
21
|
+
let protocolSelect;
|
|
22
|
+
let protocolGroup;
|
|
19
23
|
let apikeySection;
|
|
20
24
|
let oauthSection;
|
|
21
25
|
let oauthLoginBtn;
|
|
@@ -36,6 +40,10 @@ export function initApiKeyDialog() {
|
|
|
36
40
|
apiKeyInput = document.getElementById("apikey-input");
|
|
37
41
|
baseUrlInput = document.getElementById("apikey-baseurl-input");
|
|
38
42
|
baseUrlGroup = document.getElementById("apikey-baseurl-group");
|
|
43
|
+
modelIdInput = document.getElementById("apikey-modelid-input");
|
|
44
|
+
modelIdGroup = document.getElementById("apikey-modelid-group");
|
|
45
|
+
protocolSelect = document.getElementById("apikey-protocol-select");
|
|
46
|
+
protocolGroup = document.getElementById("apikey-protocol-group");
|
|
39
47
|
apikeySection = document.getElementById("apikey-apikey-section");
|
|
40
48
|
oauthSection = document.getElementById("apikey-oauth-section");
|
|
41
49
|
oauthLoginBtn = document.getElementById("oauth-login-btn");
|
|
@@ -67,6 +75,9 @@ export function initApiKeyDialog() {
|
|
|
67
75
|
if (oauthLogoutBtn) {
|
|
68
76
|
oauthLogoutBtn.addEventListener("click", handleOAuthLogout);
|
|
69
77
|
}
|
|
78
|
+
if (baseUrlInput) {
|
|
79
|
+
baseUrlInput.addEventListener("input", updateModelIdVisibility);
|
|
80
|
+
}
|
|
70
81
|
}
|
|
71
82
|
|
|
72
83
|
/**
|
|
@@ -126,6 +137,12 @@ function populateForm() {
|
|
|
126
137
|
if (baseUrlInput) {
|
|
127
138
|
baseUrlInput.value = config.baseUrl || "";
|
|
128
139
|
}
|
|
140
|
+
if (modelIdInput) {
|
|
141
|
+
modelIdInput.value = config.modelId || "";
|
|
142
|
+
}
|
|
143
|
+
if (protocolSelect) {
|
|
144
|
+
protocolSelect.value = config.apiProtocol || "openai-completions";
|
|
145
|
+
}
|
|
129
146
|
|
|
130
147
|
// OAuth Status
|
|
131
148
|
if (config.oauthConnected) {
|
|
@@ -163,6 +180,9 @@ function updateProviderUI() {
|
|
|
163
180
|
baseUrlInput.placeholder =
|
|
164
181
|
meta.baseUrlPlaceholder || "https://api.openai.com/v1";
|
|
165
182
|
}
|
|
183
|
+
|
|
184
|
+
// Show model name field only when a custom base URL is filled in
|
|
185
|
+
updateModelIdVisibility();
|
|
166
186
|
|
|
167
187
|
// Update placeholder
|
|
168
188
|
if (apiKeyInput) {
|
|
@@ -171,10 +191,21 @@ function updateProviderUI() {
|
|
|
171
191
|
}
|
|
172
192
|
}
|
|
173
193
|
|
|
194
|
+
function updateModelIdVisibility() {
|
|
195
|
+
if (!modelIdGroup) return;
|
|
196
|
+
const hasCustomUrl = baseUrlInput && baseUrlInput.value.trim().length > 0;
|
|
197
|
+
modelIdGroup.style.display = hasCustomUrl ? "" : "none";
|
|
198
|
+
if (protocolGroup) {
|
|
199
|
+
protocolGroup.style.display = hasCustomUrl ? "" : "none";
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
174
203
|
async function handleSave() {
|
|
175
204
|
const key = apiKeyInput.value.trim();
|
|
176
205
|
const provider = providerSelect.value;
|
|
177
206
|
const baseUrl = baseUrlInput.value.trim();
|
|
207
|
+
const modelId = modelIdInput ? modelIdInput.value.trim() : "";
|
|
208
|
+
const apiProtocol = protocolSelect ? protocolSelect.value : "";
|
|
178
209
|
|
|
179
210
|
// If OAuth is selected, we don't handle it here but it shouldn't happen as save button is hidden
|
|
180
211
|
const meta = state.config?.supportedProviders?.[provider];
|
|
@@ -184,6 +215,15 @@ async function handleSave() {
|
|
|
184
215
|
if (baseUrl !== state.config.baseUrl) {
|
|
185
216
|
updates.baseUrl = baseUrl;
|
|
186
217
|
}
|
|
218
|
+
if (modelId !== (state.config.modelId || "")) {
|
|
219
|
+
updates.modelId = modelId;
|
|
220
|
+
}
|
|
221
|
+
const hasCustomUrl = baseUrl.length > 0;
|
|
222
|
+
if (hasCustomUrl && apiProtocol !== (state.config.apiProtocol || "openai-completions")) {
|
|
223
|
+
updates.apiProtocol = apiProtocol;
|
|
224
|
+
} else if (!hasCustomUrl && state.config.apiProtocol) {
|
|
225
|
+
updates.apiProtocol = "";
|
|
226
|
+
}
|
|
187
227
|
|
|
188
228
|
if (key && key !== "***************************************************" && key !== state.config.apiKey) {
|
|
189
229
|
updates.key = key;
|
|
@@ -195,6 +235,8 @@ async function handleSave() {
|
|
|
195
235
|
|
|
196
236
|
state.config.provider = res.provider;
|
|
197
237
|
state.config.baseUrl = res.baseUrl || "";
|
|
238
|
+
state.config.modelId = res.modelId || "";
|
|
239
|
+
state.config.apiProtocol = res.apiProtocol || "";
|
|
198
240
|
if (updates.key) {
|
|
199
241
|
state.config.hasApiKey = true;
|
|
200
242
|
state.config.apiKey = updates.key;
|