@cremini/skillpack 1.1.8-beta.1 → 1.1.9
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/README.md +5 -1
- package/dist/cli.js +177 -256
- package/package.json +2 -2
- package/templates/builtin-skills/skill-creator/LICENSE.txt +202 -0
- package/templates/builtin-skills/skill-creator/SKILL.md +171 -0
- package/templates/builtin-skills/skill-creator/agents/analyzer.md +274 -0
- package/templates/builtin-skills/skill-creator/agents/comparator.md +202 -0
- package/templates/builtin-skills/skill-creator/agents/grader.md +223 -0
- package/templates/builtin-skills/skill-creator/assets/eval_review.html +146 -0
- package/templates/builtin-skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/templates/builtin-skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/templates/builtin-skills/skill-creator/references/schemas.md +430 -0
- package/templates/builtin-skills/skill-creator/scripts/__init__.py +0 -0
- package/templates/builtin-skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/templates/builtin-skills/skill-creator/scripts/generate_report.py +326 -0
- package/templates/builtin-skills/skill-creator/scripts/improve_description.py +247 -0
- package/templates/builtin-skills/skill-creator/scripts/package_skill.py +136 -0
- package/templates/builtin-skills/skill-creator/scripts/quick_validate.py +103 -0
- package/templates/builtin-skills/skill-creator/scripts/run_eval.py +310 -0
- package/templates/builtin-skills/skill-creator/scripts/run_loop.py +328 -0
- package/templates/builtin-skills/skill-creator/scripts/utils.py +47 -0
- package/web/js/api-key-dialog.js +5 -3
- package/web/js/chat-apps-dialog.js +10 -4
- package/web/js/chat.js +8 -8
- package/web/js/settings.js +8 -3
- package/dist/runtime/registry.js +0 -244
package/dist/cli.js
CHANGED
|
@@ -114,7 +114,7 @@ var init_config = __esm({
|
|
|
114
114
|
console.warn(" Warning: Failed to parse data/config.json:", err);
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
-
let { apiKey = "", provider = "openai" } = this.configData;
|
|
117
|
+
let { apiKey = "", provider = "openai", baseUrl = "" } = this.configData;
|
|
118
118
|
if (!apiKey) {
|
|
119
119
|
if (process.env.OPENAI_API_KEY) {
|
|
120
120
|
apiKey = process.env.OPENAI_API_KEY;
|
|
@@ -126,6 +126,7 @@ var init_config = __esm({
|
|
|
126
126
|
}
|
|
127
127
|
this.configData.apiKey = apiKey;
|
|
128
128
|
this.configData.provider = provider;
|
|
129
|
+
this.configData.baseUrl = baseUrl?.trim() || void 0;
|
|
129
130
|
return this.configData;
|
|
130
131
|
}
|
|
131
132
|
getConfig() {
|
|
@@ -141,6 +142,9 @@ var init_config = __esm({
|
|
|
141
142
|
}
|
|
142
143
|
if (updates.apiKey !== void 0) this.configData.apiKey = updates.apiKey;
|
|
143
144
|
if (updates.provider !== void 0) this.configData.provider = updates.provider;
|
|
145
|
+
if (updates.baseUrl !== void 0) {
|
|
146
|
+
this.configData.baseUrl = updates.baseUrl?.trim() || void 0;
|
|
147
|
+
}
|
|
144
148
|
if (updates.adapters !== void 0) {
|
|
145
149
|
const merged = { ...this.configData.adapters || {} };
|
|
146
150
|
for (const [adapterKey, adapterVal] of Object.entries(updates.adapters)) {
|
|
@@ -289,7 +293,7 @@ var telegram_exports = {};
|
|
|
289
293
|
__export(telegram_exports, {
|
|
290
294
|
TelegramAdapter: () => TelegramAdapter
|
|
291
295
|
});
|
|
292
|
-
import
|
|
296
|
+
import fs10 from "fs";
|
|
293
297
|
import TelegramBot from "node-telegram-bot-api";
|
|
294
298
|
var COMMANDS2, MAX_MESSAGE_LENGTH, ACK_REACTION, TelegramAdapter;
|
|
295
299
|
var init_telegram = __esm({
|
|
@@ -397,6 +401,7 @@ var init_telegram = __esm({
|
|
|
397
401
|
try {
|
|
398
402
|
const userText = text || "(User sent an attachment)";
|
|
399
403
|
const result = await this.agent.handleMessage(
|
|
404
|
+
"telegram",
|
|
400
405
|
channelId,
|
|
401
406
|
userText,
|
|
402
407
|
onEvent,
|
|
@@ -599,7 +604,7 @@ var init_telegram = __esm({
|
|
|
599
604
|
async sendFileSafe(chatId, filePath, caption) {
|
|
600
605
|
if (!this.bot) return;
|
|
601
606
|
try {
|
|
602
|
-
if (!
|
|
607
|
+
if (!fs10.existsSync(filePath)) {
|
|
603
608
|
console.error(`[Telegram] File not found for sending: ${filePath}`);
|
|
604
609
|
return;
|
|
605
610
|
}
|
|
@@ -619,8 +624,8 @@ var slack_exports = {};
|
|
|
619
624
|
__export(slack_exports, {
|
|
620
625
|
SlackAdapter: () => SlackAdapter
|
|
621
626
|
});
|
|
622
|
-
import
|
|
623
|
-
import
|
|
627
|
+
import fs11 from "fs";
|
|
628
|
+
import path10 from "path";
|
|
624
629
|
import { App, LogLevel } from "@slack/bolt";
|
|
625
630
|
var INLINE_COMMANDS, SLASH_COMMANDS, MAX_MESSAGE_LENGTH2, ACK_REACTION2, SlackAdapter;
|
|
626
631
|
var init_slack = __esm({
|
|
@@ -830,6 +835,7 @@ var init_slack = __esm({
|
|
|
830
835
|
};
|
|
831
836
|
try {
|
|
832
837
|
const result = await this.agent.handleMessage(
|
|
838
|
+
"slack",
|
|
833
839
|
channelId,
|
|
834
840
|
text,
|
|
835
841
|
onEvent,
|
|
@@ -1097,12 +1103,12 @@ var init_slack = __esm({
|
|
|
1097
1103
|
*/
|
|
1098
1104
|
async sendFileSafe(client, route, filePath, caption) {
|
|
1099
1105
|
try {
|
|
1100
|
-
if (!
|
|
1106
|
+
if (!fs11.existsSync(filePath)) {
|
|
1101
1107
|
console.error(`[Slack] File not found for sending: ${filePath}`);
|
|
1102
1108
|
return;
|
|
1103
1109
|
}
|
|
1104
|
-
const filename =
|
|
1105
|
-
const fileContent =
|
|
1110
|
+
const filename = path10.basename(filePath);
|
|
1111
|
+
const fileContent = fs11.readFileSync(filePath);
|
|
1106
1112
|
await client.files.uploadV2({
|
|
1107
1113
|
channel_id: route.channel,
|
|
1108
1114
|
thread_ts: route.threadTs,
|
|
@@ -1274,6 +1280,7 @@ var init_scheduler = __esm({
|
|
|
1274
1280
|
};
|
|
1275
1281
|
try {
|
|
1276
1282
|
const result = await this.agent.handleMessage(
|
|
1283
|
+
"scheduler",
|
|
1277
1284
|
channelId,
|
|
1278
1285
|
jobConfig.prompt,
|
|
1279
1286
|
onEvent
|
|
@@ -2036,16 +2043,16 @@ async function interactiveCreate(workDir) {
|
|
|
2036
2043
|
}
|
|
2037
2044
|
|
|
2038
2045
|
// src/commands/run.ts
|
|
2039
|
-
import
|
|
2040
|
-
import
|
|
2046
|
+
import path12 from "path";
|
|
2047
|
+
import fs13 from "fs";
|
|
2041
2048
|
import inquirer2 from "inquirer";
|
|
2042
2049
|
import chalk4 from "chalk";
|
|
2043
2050
|
|
|
2044
2051
|
// src/runtime/server.ts
|
|
2045
2052
|
import express from "express";
|
|
2046
|
-
import
|
|
2047
|
-
import
|
|
2048
|
-
import { fileURLToPath } from "url";
|
|
2053
|
+
import path11 from "path";
|
|
2054
|
+
import fs12 from "fs";
|
|
2055
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2049
2056
|
import { createServer } from "http";
|
|
2050
2057
|
import { exec } from "child_process";
|
|
2051
2058
|
|
|
@@ -2053,6 +2060,7 @@ import { exec } from "child_process";
|
|
|
2053
2060
|
init_attachment_utils();
|
|
2054
2061
|
import path7 from "path";
|
|
2055
2062
|
import fs7 from "fs";
|
|
2063
|
+
import { fileURLToPath } from "url";
|
|
2056
2064
|
import {
|
|
2057
2065
|
AuthStorage,
|
|
2058
2066
|
createAgentSession,
|
|
@@ -4785,16 +4793,6 @@ var ManageScheduleParams = Type.Object({
|
|
|
4785
4793
|
description: "The work prompt to execute when the task triggers. Required for add. Describe only what to do each run; do not repeat timing, cron, or 'every N minutes' instructions here."
|
|
4786
4794
|
})
|
|
4787
4795
|
),
|
|
4788
|
-
notifyAdapter: Type.Optional(
|
|
4789
|
-
Type.String({
|
|
4790
|
-
description: "Target adapter name for result notification: 'telegram' or 'slack'. Required for add."
|
|
4791
|
-
})
|
|
4792
|
-
),
|
|
4793
|
-
notifyChannelId: Type.Optional(
|
|
4794
|
-
Type.String({
|
|
4795
|
-
description: "Target channelId for result notification (e.g. 'telegram-123456'). Required for add."
|
|
4796
|
-
})
|
|
4797
|
-
),
|
|
4798
4796
|
timezone: Type.Optional(
|
|
4799
4797
|
Type.String({
|
|
4800
4798
|
description: "Optional timezone for the cron schedule, e.g. 'Asia/Shanghai', 'America/New_York'."
|
|
@@ -4804,7 +4802,7 @@ var ManageScheduleParams = Type.Object({
|
|
|
4804
4802
|
function textResult(text) {
|
|
4805
4803
|
return { content: [{ type: "text", text }], details: void 0 };
|
|
4806
4804
|
}
|
|
4807
|
-
function createManageScheduleTool(schedulerRef,
|
|
4805
|
+
function createManageScheduleTool(schedulerRef, adapter, channelId) {
|
|
4808
4806
|
return {
|
|
4809
4807
|
name: "manage_scheduled_task",
|
|
4810
4808
|
label: "Manage Scheduled Task",
|
|
@@ -4812,7 +4810,7 @@ function createManageScheduleTool(schedulerRef, _rootDirRef) {
|
|
|
4812
4810
|
"Manage scheduled tasks (cron jobs) that automatically execute prompts and push results to IM channels.",
|
|
4813
4811
|
"",
|
|
4814
4812
|
"Actions:",
|
|
4815
|
-
"- add: Create a new scheduled task. Requires: name, cron, prompt
|
|
4813
|
+
"- add: Create a new scheduled task. Requires: name, cron, prompt. The notification target always uses the current Telegram or Slack chat. The prompt must describe only the work for each run, not the schedule itself.",
|
|
4816
4814
|
"- list: List all scheduled tasks with their status.",
|
|
4817
4815
|
"- remove: Remove a scheduled task by name.",
|
|
4818
4816
|
"- trigger: Manually trigger a scheduled task by name (runs immediately).",
|
|
@@ -4823,10 +4821,7 @@ function createManageScheduleTool(schedulerRef, _rootDirRef) {
|
|
|
4823
4821
|
"Examples:",
|
|
4824
4822
|
" '0 9 * * 1-5' = every weekday at 9:00 AM",
|
|
4825
4823
|
" '0 18 * * 5' = every Friday at 6:00 PM",
|
|
4826
|
-
" '*/30 * * * *' = every 30 minutes"
|
|
4827
|
-
"",
|
|
4828
|
-
"notifyAdapter: 'telegram' or 'slack'",
|
|
4829
|
-
"notifyChannelId: the channel ID where result will be sent (e.g. 'telegram-123456')"
|
|
4824
|
+
" '*/30 * * * *' = every 30 minutes"
|
|
4830
4825
|
].join("\n"),
|
|
4831
4826
|
parameters: ManageScheduleParams,
|
|
4832
4827
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
@@ -4856,9 +4851,9 @@ ${lines.join("\n")}`
|
|
|
4856
4851
|
"Error: 'name', 'cron', and 'prompt' are required for adding a task."
|
|
4857
4852
|
);
|
|
4858
4853
|
}
|
|
4859
|
-
if (
|
|
4854
|
+
if (adapter !== "telegram" && adapter !== "slack") {
|
|
4860
4855
|
return textResult(
|
|
4861
|
-
"Error:
|
|
4856
|
+
"Error: Scheduled tasks can only be created from a Telegram or Slack."
|
|
4862
4857
|
);
|
|
4863
4858
|
}
|
|
4864
4859
|
const jobConfig = {
|
|
@@ -4866,8 +4861,8 @@ ${lines.join("\n")}`
|
|
|
4866
4861
|
cron: params.cron,
|
|
4867
4862
|
prompt: params.prompt,
|
|
4868
4863
|
notify: {
|
|
4869
|
-
adapter
|
|
4870
|
-
channelId
|
|
4864
|
+
adapter,
|
|
4865
|
+
channelId
|
|
4871
4866
|
},
|
|
4872
4867
|
enabled: true,
|
|
4873
4868
|
timezone: params.timezone
|
|
@@ -4924,6 +4919,75 @@ ${lines.join("\n")}`
|
|
|
4924
4919
|
var DEBUG = true;
|
|
4925
4920
|
var log = (...args) => DEBUG && console.log(...args);
|
|
4926
4921
|
var write = (data) => DEBUG && process.stdout.write(data);
|
|
4922
|
+
var BUILTIN_SKILL_CREATOR_NAME = "skill-creator";
|
|
4923
|
+
var BUILTIN_SKILL_CREATOR_DESCRIPTION = "Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.";
|
|
4924
|
+
var BUILTIN_SKILL_CREATOR_TEMPLATE_DIR = fileURLToPath(
|
|
4925
|
+
new URL("../templates/builtin-skills/skill-creator", import.meta.url)
|
|
4926
|
+
);
|
|
4927
|
+
function materializeBuiltinSkillCreator(rootDir, skillsPath) {
|
|
4928
|
+
if (!fs7.existsSync(BUILTIN_SKILL_CREATOR_TEMPLATE_DIR)) {
|
|
4929
|
+
log(
|
|
4930
|
+
`[PackAgent] Built-in skill-creator template missing: ${BUILTIN_SKILL_CREATOR_TEMPLATE_DIR}`
|
|
4931
|
+
);
|
|
4932
|
+
return null;
|
|
4933
|
+
}
|
|
4934
|
+
const packConfigPath = path7.resolve(rootDir, "skillpack.json");
|
|
4935
|
+
const skillDir = path7.resolve(skillsPath, BUILTIN_SKILL_CREATOR_NAME);
|
|
4936
|
+
const skillPath = path7.join(skillDir, "SKILL.md");
|
|
4937
|
+
const renderTemplate = (content) => content.replaceAll("{{SKILLS_PATH}}", skillsPath).replaceAll("{{PACK_CONFIG_PATH}}", packConfigPath);
|
|
4938
|
+
const copyDir = (srcDir, destDir) => {
|
|
4939
|
+
fs7.mkdirSync(destDir, { recursive: true });
|
|
4940
|
+
for (const entry of fs7.readdirSync(srcDir, { withFileTypes: true })) {
|
|
4941
|
+
if (entry.name === ".DS_Store") {
|
|
4942
|
+
continue;
|
|
4943
|
+
}
|
|
4944
|
+
const srcPath = path7.join(srcDir, entry.name);
|
|
4945
|
+
const destPath = path7.join(destDir, entry.name);
|
|
4946
|
+
if (entry.isDirectory()) {
|
|
4947
|
+
copyDir(srcPath, destPath);
|
|
4948
|
+
continue;
|
|
4949
|
+
}
|
|
4950
|
+
if (!entry.isFile()) {
|
|
4951
|
+
continue;
|
|
4952
|
+
}
|
|
4953
|
+
if (entry.name.endsWith(".md") || entry.name.endsWith(".py")) {
|
|
4954
|
+
const content = fs7.readFileSync(srcPath, "utf-8");
|
|
4955
|
+
fs7.writeFileSync(destPath, renderTemplate(content), "utf-8");
|
|
4956
|
+
continue;
|
|
4957
|
+
}
|
|
4958
|
+
fs7.copyFileSync(srcPath, destPath);
|
|
4959
|
+
}
|
|
4960
|
+
};
|
|
4961
|
+
if (!fs7.existsSync(skillDir)) {
|
|
4962
|
+
copyDir(BUILTIN_SKILL_CREATOR_TEMPLATE_DIR, skillDir);
|
|
4963
|
+
}
|
|
4964
|
+
if (!fs7.existsSync(skillPath)) {
|
|
4965
|
+
log(
|
|
4966
|
+
`[PackAgent] Materialized built-in skill-creator but SKILL.md is missing: ${skillPath}`
|
|
4967
|
+
);
|
|
4968
|
+
return null;
|
|
4969
|
+
}
|
|
4970
|
+
return {
|
|
4971
|
+
name: BUILTIN_SKILL_CREATOR_NAME,
|
|
4972
|
+
description: BUILTIN_SKILL_CREATOR_DESCRIPTION,
|
|
4973
|
+
filePath: skillPath,
|
|
4974
|
+
baseDir: skillDir,
|
|
4975
|
+
source: "path",
|
|
4976
|
+
disableModelInvocation: false
|
|
4977
|
+
};
|
|
4978
|
+
}
|
|
4979
|
+
function overrideBuiltinSkillCreator(base, materializedSkill) {
|
|
4980
|
+
if (!materializedSkill) {
|
|
4981
|
+
return base;
|
|
4982
|
+
}
|
|
4983
|
+
const filtered = base.skills.filter(
|
|
4984
|
+
(skill) => skill.name !== BUILTIN_SKILL_CREATOR_NAME
|
|
4985
|
+
);
|
|
4986
|
+
return {
|
|
4987
|
+
skills: [materializedSkill, ...filtered],
|
|
4988
|
+
diagnostics: base.diagnostics
|
|
4989
|
+
};
|
|
4990
|
+
}
|
|
4927
4991
|
function getAssistantDiagnostics(message) {
|
|
4928
4992
|
if (!message || message.role !== "assistant") {
|
|
4929
4993
|
return null;
|
|
@@ -4949,17 +5013,9 @@ var PackAgent = class {
|
|
|
4949
5013
|
fileOutputCallbackRef = {
|
|
4950
5014
|
current: null
|
|
4951
5015
|
};
|
|
4952
|
-
sendFileToolDef = createSendFileTool(this.fileOutputCallbackRef);
|
|
4953
5016
|
schedulerRef = { current: null };
|
|
4954
|
-
rootDirRef;
|
|
4955
|
-
scheduleToolDef;
|
|
4956
5017
|
constructor(options) {
|
|
4957
5018
|
this.options = options;
|
|
4958
|
-
this.rootDirRef = { current: options.rootDir };
|
|
4959
|
-
this.scheduleToolDef = createManageScheduleTool(
|
|
4960
|
-
this.schedulerRef,
|
|
4961
|
-
this.rootDirRef
|
|
4962
|
-
);
|
|
4963
5019
|
}
|
|
4964
5020
|
/**
|
|
4965
5021
|
* Inject scheduler reference (called by server.ts after adapter init).
|
|
@@ -4967,22 +5023,33 @@ var PackAgent = class {
|
|
|
4967
5023
|
setScheduler(scheduler) {
|
|
4968
5024
|
this.schedulerRef.current = scheduler;
|
|
4969
5025
|
}
|
|
5026
|
+
createCustomTools(adapter, channelId) {
|
|
5027
|
+
const tools = [createSendFileTool(this.fileOutputCallbackRef)];
|
|
5028
|
+
if (adapter === "telegram" || adapter === "slack") {
|
|
5029
|
+
tools.push(createManageScheduleTool(this.schedulerRef, adapter, channelId));
|
|
5030
|
+
}
|
|
5031
|
+
return tools;
|
|
5032
|
+
}
|
|
4970
5033
|
/**
|
|
4971
5034
|
* Lazily create (or return existing) session for a channel.
|
|
4972
5035
|
*/
|
|
4973
|
-
async getOrCreateSession(channelId) {
|
|
5036
|
+
async getOrCreateSession(adapter, channelId) {
|
|
4974
5037
|
const existing = this.channels.get(channelId);
|
|
4975
5038
|
if (existing) return existing;
|
|
4976
5039
|
const pendingCreation = this.pendingSessionCreations.get(channelId);
|
|
4977
5040
|
if (pendingCreation) return pendingCreation;
|
|
4978
5041
|
const createSessionPromise = (async () => {
|
|
4979
|
-
const { apiKey, rootDir, provider, modelId } = this.options;
|
|
5042
|
+
const { apiKey, rootDir, provider, modelId, baseUrl } = this.options;
|
|
4980
5043
|
const authStorage = AuthStorage.inMemory({
|
|
4981
5044
|
[provider]: { type: "api_key", key: apiKey }
|
|
4982
5045
|
});
|
|
4983
5046
|
authStorage.setRuntimeApiKey(provider, apiKey);
|
|
4984
5047
|
const modelRegistry = new ModelRegistry(authStorage);
|
|
4985
|
-
const
|
|
5048
|
+
const resolvedModel = modelRegistry.find(provider, modelId);
|
|
5049
|
+
const model = resolvedModel && baseUrl ? { ...resolvedModel, baseUrl } : resolvedModel;
|
|
5050
|
+
if (resolvedModel && baseUrl) {
|
|
5051
|
+
log(`[PackAgent] Overriding ${provider}/${modelId} baseUrl -> ${baseUrl}`);
|
|
5052
|
+
}
|
|
4986
5053
|
const sessionDir = path7.resolve(
|
|
4987
5054
|
rootDir,
|
|
4988
5055
|
"data",
|
|
@@ -5002,12 +5069,23 @@ var PackAgent = class {
|
|
|
5002
5069
|
log(`[PackAgent] Workspace dir: ${workspaceDir}`);
|
|
5003
5070
|
const skillsPath = path7.resolve(rootDir, "skills");
|
|
5004
5071
|
log(`[PackAgent] Loading skills from: ${skillsPath}`);
|
|
5072
|
+
const materializedSkillCreator = materializeBuiltinSkillCreator(
|
|
5073
|
+
rootDir,
|
|
5074
|
+
skillsPath
|
|
5075
|
+
);
|
|
5076
|
+
if (materializedSkillCreator) {
|
|
5077
|
+
log(
|
|
5078
|
+
`[PackAgent] Materialized built-in skill-creator to: ${materializedSkillCreator.filePath}`
|
|
5079
|
+
);
|
|
5080
|
+
}
|
|
5005
5081
|
const resourceLoader = new DefaultResourceLoader({
|
|
5006
5082
|
cwd: rootDir,
|
|
5007
|
-
additionalSkillPaths: [skillsPath]
|
|
5083
|
+
additionalSkillPaths: [skillsPath],
|
|
5084
|
+
skillsOverride: (base) => overrideBuiltinSkillCreator(base, materializedSkillCreator)
|
|
5008
5085
|
});
|
|
5009
5086
|
await resourceLoader.reload();
|
|
5010
5087
|
const tools = createCodingTools(workspaceDir);
|
|
5088
|
+
const customTools = this.createCustomTools(adapter, channelId);
|
|
5011
5089
|
const { session } = await createAgentSession({
|
|
5012
5090
|
cwd: workspaceDir,
|
|
5013
5091
|
authStorage,
|
|
@@ -5016,7 +5094,7 @@ var PackAgent = class {
|
|
|
5016
5094
|
resourceLoader,
|
|
5017
5095
|
model,
|
|
5018
5096
|
tools,
|
|
5019
|
-
customTools
|
|
5097
|
+
customTools
|
|
5020
5098
|
});
|
|
5021
5099
|
const channelSession = {
|
|
5022
5100
|
session,
|
|
@@ -5033,8 +5111,8 @@ var PackAgent = class {
|
|
|
5033
5111
|
this.pendingSessionCreations.delete(channelId);
|
|
5034
5112
|
}
|
|
5035
5113
|
}
|
|
5036
|
-
async handleMessage(channelId, text, onEvent, attachments) {
|
|
5037
|
-
const cs = await this.getOrCreateSession(channelId);
|
|
5114
|
+
async handleMessage(adapter, channelId, text, onEvent, attachments) {
|
|
5115
|
+
const cs = await this.getOrCreateSession(adapter, channelId);
|
|
5038
5116
|
const run = async () => {
|
|
5039
5117
|
cs.running = true;
|
|
5040
5118
|
let turnHadVisibleOutput = false;
|
|
@@ -5243,6 +5321,7 @@ function getRuntimeConfigSignature(config) {
|
|
|
5243
5321
|
return JSON.stringify({
|
|
5244
5322
|
apiKey: config.apiKey || "",
|
|
5245
5323
|
provider: config.provider || "openai",
|
|
5324
|
+
baseUrl: config.baseUrl || "",
|
|
5246
5325
|
telegramToken: config.adapters?.telegram?.token || "",
|
|
5247
5326
|
slackBotToken: config.adapters?.slack?.botToken || "",
|
|
5248
5327
|
slackAppToken: config.adapters?.slack?.appToken || ""
|
|
@@ -5269,7 +5348,9 @@ var WebAdapter = class {
|
|
|
5269
5348
|
hasApiKey: !!conf.apiKey,
|
|
5270
5349
|
apiKey: conf.apiKey || "",
|
|
5271
5350
|
provider: conf.provider || "openai",
|
|
5272
|
-
|
|
5351
|
+
baseUrl: conf.baseUrl || "",
|
|
5352
|
+
adapters: conf.adapters || {},
|
|
5353
|
+
runtimeControl: lifecycle.getRuntimeControl()
|
|
5273
5354
|
});
|
|
5274
5355
|
});
|
|
5275
5356
|
app.get("/api/skills", (_req, res) => {
|
|
@@ -5277,7 +5358,7 @@ var WebAdapter = class {
|
|
|
5277
5358
|
res.json(config.skills || []);
|
|
5278
5359
|
});
|
|
5279
5360
|
app.post("/api/config/update", (req, res) => {
|
|
5280
|
-
const { key, provider, adapters } = req.body;
|
|
5361
|
+
const { key, provider, baseUrl, adapters } = req.body;
|
|
5281
5362
|
const updates = {};
|
|
5282
5363
|
const beforeConfig = JSON.parse(JSON.stringify(configManager.getConfig()));
|
|
5283
5364
|
if (key !== void 0) {
|
|
@@ -5288,6 +5369,9 @@ var WebAdapter = class {
|
|
|
5288
5369
|
updates.provider = provider;
|
|
5289
5370
|
currentProvider = provider;
|
|
5290
5371
|
}
|
|
5372
|
+
if (baseUrl !== void 0) {
|
|
5373
|
+
updates.baseUrl = baseUrl;
|
|
5374
|
+
}
|
|
5291
5375
|
if (adapters !== void 0) {
|
|
5292
5376
|
updates.adapters = adapters;
|
|
5293
5377
|
}
|
|
@@ -5297,13 +5381,24 @@ var WebAdapter = class {
|
|
|
5297
5381
|
res.json({
|
|
5298
5382
|
success: true,
|
|
5299
5383
|
provider: newConf.provider,
|
|
5384
|
+
baseUrl: newConf.baseUrl || "",
|
|
5300
5385
|
adapters: newConf.adapters,
|
|
5301
|
-
requiresRestart
|
|
5386
|
+
requiresRestart,
|
|
5387
|
+
runtimeControl: lifecycle.getRuntimeControl()
|
|
5302
5388
|
});
|
|
5303
5389
|
});
|
|
5304
5390
|
app.post("/api/runtime/restart", async (_req, res) => {
|
|
5391
|
+
const runtimeControl = lifecycle.getRuntimeControl();
|
|
5392
|
+
if (!runtimeControl.canManagedRestart) {
|
|
5393
|
+
res.status(409).json({
|
|
5394
|
+
success: false,
|
|
5395
|
+
message: "Managed restart is unavailable for this process.",
|
|
5396
|
+
runtimeControl
|
|
5397
|
+
});
|
|
5398
|
+
return;
|
|
5399
|
+
}
|
|
5305
5400
|
const result = await lifecycle.requestRestart("web");
|
|
5306
|
-
res.status(202).json(result);
|
|
5401
|
+
res.status(202).json({ ...result, runtimeControl });
|
|
5307
5402
|
});
|
|
5308
5403
|
app.delete("/api/chat", (_req, res) => {
|
|
5309
5404
|
res.json({ success: true });
|
|
@@ -5472,7 +5567,7 @@ var WebAdapter = class {
|
|
|
5472
5567
|
if (ws.readyState !== ws.OPEN) return;
|
|
5473
5568
|
ws.send(JSON.stringify(event));
|
|
5474
5569
|
};
|
|
5475
|
-
const result = await agent.handleMessage(channelId, text, onEvent);
|
|
5570
|
+
const result = await agent.handleMessage("web", channelId, text, onEvent);
|
|
5476
5571
|
if (result.errorMessage) {
|
|
5477
5572
|
ws.send(JSON.stringify({ error: result.errorMessage }));
|
|
5478
5573
|
return;
|
|
@@ -5495,18 +5590,29 @@ init_config();
|
|
|
5495
5590
|
var SHUTDOWN_EXIT_CODE = 64;
|
|
5496
5591
|
var RESTART_EXIT_CODE = 75;
|
|
5497
5592
|
var STOP_TIMEOUT_MS = 3e3;
|
|
5593
|
+
function detectProcessManager() {
|
|
5594
|
+
return process.env.PACK_ROOT ? "wrapper" : "none";
|
|
5595
|
+
}
|
|
5498
5596
|
var Lifecycle = class {
|
|
5499
5597
|
server;
|
|
5500
5598
|
exitFn;
|
|
5599
|
+
processManager;
|
|
5501
5600
|
adapters = [];
|
|
5502
5601
|
stopReason = null;
|
|
5503
5602
|
constructor(server, exitFn = (code) => process.exit(code)) {
|
|
5504
5603
|
this.server = server;
|
|
5505
5604
|
this.exitFn = exitFn;
|
|
5605
|
+
this.processManager = detectProcessManager();
|
|
5506
5606
|
}
|
|
5507
5607
|
registerAdapters(adapters) {
|
|
5508
5608
|
this.adapters = adapters;
|
|
5509
5609
|
}
|
|
5610
|
+
getRuntimeControl() {
|
|
5611
|
+
return {
|
|
5612
|
+
canManagedRestart: this.processManager === "wrapper",
|
|
5613
|
+
processManager: this.processManager
|
|
5614
|
+
};
|
|
5615
|
+
}
|
|
5510
5616
|
async requestRestart(trigger) {
|
|
5511
5617
|
return this.requestStop("restart", trigger);
|
|
5512
5618
|
}
|
|
@@ -5562,203 +5668,33 @@ var Lifecycle = class {
|
|
|
5562
5668
|
}
|
|
5563
5669
|
};
|
|
5564
5670
|
|
|
5565
|
-
// src/runtime/registry.ts
|
|
5566
|
-
import crypto from "crypto";
|
|
5567
|
-
import fs10 from "fs";
|
|
5568
|
-
import os from "os";
|
|
5569
|
-
import path10 from "path";
|
|
5570
|
-
var SKILLPACK_HOME = path10.join(os.homedir(), ".skillpack");
|
|
5571
|
-
var LEGACY_REGISTRY_FILE = path10.join(SKILLPACK_HOME, "registry.json");
|
|
5572
|
-
var REGISTRY_DIR = path10.join(SKILLPACK_HOME, "registry.d");
|
|
5573
|
-
var migrationChecked = false;
|
|
5574
|
-
function ensureHomeDir() {
|
|
5575
|
-
if (!fs10.existsSync(SKILLPACK_HOME)) {
|
|
5576
|
-
fs10.mkdirSync(SKILLPACK_HOME, { recursive: true });
|
|
5577
|
-
}
|
|
5578
|
-
}
|
|
5579
|
-
function ensureRegistryDir() {
|
|
5580
|
-
ensureHomeDir();
|
|
5581
|
-
if (!fs10.existsSync(REGISTRY_DIR)) {
|
|
5582
|
-
fs10.mkdirSync(REGISTRY_DIR, { recursive: true });
|
|
5583
|
-
}
|
|
5584
|
-
}
|
|
5585
|
-
function canonicalizeDir(dir) {
|
|
5586
|
-
const resolved = path10.resolve(dir);
|
|
5587
|
-
try {
|
|
5588
|
-
return fs10.realpathSync(resolved);
|
|
5589
|
-
} catch {
|
|
5590
|
-
return resolved;
|
|
5591
|
-
}
|
|
5592
|
-
}
|
|
5593
|
-
function hashDir(dir) {
|
|
5594
|
-
return crypto.createHash("md5").update(canonicalizeDir(dir)).digest("hex");
|
|
5595
|
-
}
|
|
5596
|
-
function getEntryPathForCanonicalDir(dir) {
|
|
5597
|
-
return path10.join(REGISTRY_DIR, `${hashDir(dir)}.json`);
|
|
5598
|
-
}
|
|
5599
|
-
function getEntryPath(dir) {
|
|
5600
|
-
ensureRegistryReady();
|
|
5601
|
-
return getEntryPathForCanonicalDir(canonicalizeDir(dir));
|
|
5602
|
-
}
|
|
5603
|
-
function listEntryFiles() {
|
|
5604
|
-
ensureRegistryReady();
|
|
5605
|
-
return fs10.readdirSync(REGISTRY_DIR).filter((file) => file.endsWith(".json")).sort().map((file) => path10.join(REGISTRY_DIR, file));
|
|
5606
|
-
}
|
|
5607
|
-
function readEntryFile(filePath) {
|
|
5608
|
-
try {
|
|
5609
|
-
const raw = fs10.readFileSync(filePath, "utf-8");
|
|
5610
|
-
const data = JSON.parse(raw);
|
|
5611
|
-
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") {
|
|
5612
|
-
return null;
|
|
5613
|
-
}
|
|
5614
|
-
return {
|
|
5615
|
-
dir: canonicalizeDir(data.dir),
|
|
5616
|
-
name: data.name,
|
|
5617
|
-
version: data.version,
|
|
5618
|
-
port: data.port,
|
|
5619
|
-
pid: data.pid,
|
|
5620
|
-
status: data.status,
|
|
5621
|
-
startedAt: data.startedAt,
|
|
5622
|
-
stoppedAt: data.stoppedAt,
|
|
5623
|
-
updatedAt: data.updatedAt
|
|
5624
|
-
};
|
|
5625
|
-
} catch {
|
|
5626
|
-
return null;
|
|
5627
|
-
}
|
|
5628
|
-
}
|
|
5629
|
-
function createTmpPath(entryPath) {
|
|
5630
|
-
const suffix = `${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}`;
|
|
5631
|
-
return `${entryPath}.tmp.${suffix}`;
|
|
5632
|
-
}
|
|
5633
|
-
function writeEntryFile(entry) {
|
|
5634
|
-
ensureRegistryReady();
|
|
5635
|
-
const normalized = {
|
|
5636
|
-
...entry,
|
|
5637
|
-
dir: canonicalizeDir(entry.dir),
|
|
5638
|
-
updatedAt: entry.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
5639
|
-
};
|
|
5640
|
-
const entryPath = getEntryPathForCanonicalDir(normalized.dir);
|
|
5641
|
-
const tmpPath = createTmpPath(entryPath);
|
|
5642
|
-
fs10.writeFileSync(tmpPath, JSON.stringify(normalized, null, 2), "utf-8");
|
|
5643
|
-
fs10.renameSync(tmpPath, entryPath);
|
|
5644
|
-
}
|
|
5645
|
-
function migrateLegacyRegistryIfNeeded() {
|
|
5646
|
-
if (migrationChecked) {
|
|
5647
|
-
return;
|
|
5648
|
-
}
|
|
5649
|
-
migrationChecked = true;
|
|
5650
|
-
ensureRegistryDir();
|
|
5651
|
-
if (!fs10.existsSync(LEGACY_REGISTRY_FILE)) {
|
|
5652
|
-
return;
|
|
5653
|
-
}
|
|
5654
|
-
if (listEntryFiles().length > 0) {
|
|
5655
|
-
return;
|
|
5656
|
-
}
|
|
5657
|
-
try {
|
|
5658
|
-
const raw = fs10.readFileSync(LEGACY_REGISTRY_FILE, "utf-8");
|
|
5659
|
-
const data = JSON.parse(raw);
|
|
5660
|
-
const packs = Array.isArray(data?.packs) ? data.packs : [];
|
|
5661
|
-
for (const pack of packs) {
|
|
5662
|
-
try {
|
|
5663
|
-
writeEntryFile({
|
|
5664
|
-
...pack,
|
|
5665
|
-
dir: canonicalizeDir(pack.dir),
|
|
5666
|
-
updatedAt: pack.updatedAt ?? pack.stoppedAt ?? pack.startedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
5667
|
-
});
|
|
5668
|
-
} catch {
|
|
5669
|
-
}
|
|
5670
|
-
}
|
|
5671
|
-
fs10.renameSync(LEGACY_REGISTRY_FILE, `${LEGACY_REGISTRY_FILE}.legacy`);
|
|
5672
|
-
} catch (err) {
|
|
5673
|
-
console.warn(" [Registry] Failed to migrate legacy registry.json:", err);
|
|
5674
|
-
}
|
|
5675
|
-
}
|
|
5676
|
-
function ensureRegistryReady() {
|
|
5677
|
-
ensureRegistryDir();
|
|
5678
|
-
migrateLegacyRegistryIfNeeded();
|
|
5679
|
-
}
|
|
5680
|
-
function readEntry(dir) {
|
|
5681
|
-
ensureRegistryReady();
|
|
5682
|
-
return readEntryFile(getEntryPath(dir));
|
|
5683
|
-
}
|
|
5684
|
-
function register(opts) {
|
|
5685
|
-
try {
|
|
5686
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5687
|
-
const entry = {
|
|
5688
|
-
dir: canonicalizeDir(opts.dir),
|
|
5689
|
-
name: opts.name,
|
|
5690
|
-
version: opts.version,
|
|
5691
|
-
port: opts.port,
|
|
5692
|
-
pid: process.pid,
|
|
5693
|
-
status: "running",
|
|
5694
|
-
startedAt: now,
|
|
5695
|
-
updatedAt: now
|
|
5696
|
-
};
|
|
5697
|
-
writeEntryFile(entry);
|
|
5698
|
-
console.log(` [Registry] Registered "${opts.name}" (pid ${process.pid})`);
|
|
5699
|
-
} catch (err) {
|
|
5700
|
-
console.warn(" [Registry] Failed to register:", err);
|
|
5701
|
-
}
|
|
5702
|
-
}
|
|
5703
|
-
function deregister(dir, pid) {
|
|
5704
|
-
try {
|
|
5705
|
-
const entry = readEntry(dir);
|
|
5706
|
-
if (!entry || entry.pid !== pid) {
|
|
5707
|
-
return;
|
|
5708
|
-
}
|
|
5709
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5710
|
-
writeEntryFile({
|
|
5711
|
-
...entry,
|
|
5712
|
-
pid: null,
|
|
5713
|
-
status: "stopped",
|
|
5714
|
-
stoppedAt: now,
|
|
5715
|
-
updatedAt: now
|
|
5716
|
-
});
|
|
5717
|
-
console.log(` [Registry] Deregistered "${entry.name}"`);
|
|
5718
|
-
} catch (err) {
|
|
5719
|
-
console.warn(" [Registry] Failed to deregister:", err);
|
|
5720
|
-
}
|
|
5721
|
-
}
|
|
5722
|
-
|
|
5723
5671
|
// src/runtime/server.ts
|
|
5724
|
-
var __dirname =
|
|
5672
|
+
var __dirname = path11.dirname(fileURLToPath2(import.meta.url));
|
|
5725
5673
|
async function startServer(options) {
|
|
5726
5674
|
const {
|
|
5727
5675
|
rootDir,
|
|
5728
5676
|
host = process.env.HOST || "127.0.0.1",
|
|
5729
5677
|
port = Number(process.env.PORT) || 26313,
|
|
5730
|
-
|
|
5678
|
+
firstRun = true
|
|
5731
5679
|
} = options;
|
|
5732
5680
|
const dataConfig = configManager.load(rootDir);
|
|
5733
5681
|
const apiKey = dataConfig.apiKey || "";
|
|
5734
5682
|
const provider = dataConfig.provider || "openai";
|
|
5735
|
-
const
|
|
5736
|
-
const packConfig = loadConfig(canonicalRootDir);
|
|
5683
|
+
const baseUrl = dataConfig.baseUrl?.trim() || void 0;
|
|
5737
5684
|
const modelId = provider === "anthropic" ? "claude-opus-4-6" : "gpt-5.4";
|
|
5738
|
-
const packageRoot =
|
|
5739
|
-
const webDir =
|
|
5685
|
+
const packageRoot = path11.resolve(__dirname, "..");
|
|
5686
|
+
const webDir = fs12.existsSync(path11.join(rootDir, "web")) ? path11.join(rootDir, "web") : path11.join(packageRoot, "web");
|
|
5740
5687
|
const app = express();
|
|
5741
5688
|
app.use(express.json());
|
|
5742
5689
|
app.use(express.static(webDir));
|
|
5743
5690
|
const server = createServer(app);
|
|
5744
|
-
app.get("/api/health", (_req, res) => {
|
|
5745
|
-
const address = server.address();
|
|
5746
|
-
const actualPort = typeof address === "string" ? port : address?.port ?? port;
|
|
5747
|
-
res.json({
|
|
5748
|
-
status: "ok",
|
|
5749
|
-
dir: canonicalRootDir,
|
|
5750
|
-
name: packConfig.name,
|
|
5751
|
-
version: packConfig.version,
|
|
5752
|
-
port: actualPort,
|
|
5753
|
-
pid: process.pid
|
|
5754
|
-
});
|
|
5755
|
-
});
|
|
5756
5691
|
const lifecycle = new Lifecycle(server);
|
|
5757
5692
|
const agent = new PackAgent({
|
|
5758
5693
|
apiKey,
|
|
5759
5694
|
rootDir,
|
|
5760
5695
|
provider,
|
|
5761
5696
|
modelId,
|
|
5697
|
+
baseUrl,
|
|
5762
5698
|
lifecycleHandler: lifecycle
|
|
5763
5699
|
});
|
|
5764
5700
|
const adapters = [];
|
|
@@ -5846,17 +5782,7 @@ async function startServer(options) {
|
|
|
5846
5782
|
Skills Pack Server`);
|
|
5847
5783
|
console.log(` Running at ${url}
|
|
5848
5784
|
`);
|
|
5849
|
-
|
|
5850
|
-
register({
|
|
5851
|
-
dir: canonicalRootDir,
|
|
5852
|
-
name: packConfig.name,
|
|
5853
|
-
version: packConfig.version,
|
|
5854
|
-
port: typeof actualPort === "number" ? actualPort : port
|
|
5855
|
-
});
|
|
5856
|
-
} catch (err) {
|
|
5857
|
-
console.warn(" [Registry] Could not register pack:", err);
|
|
5858
|
-
}
|
|
5859
|
-
if (!daemonRun) {
|
|
5785
|
+
if (firstRun) {
|
|
5860
5786
|
const cmd = process.platform === "darwin" ? `open ${url}` : process.platform === "win32" ? `start ${url}` : `xdg-open ${url}`;
|
|
5861
5787
|
exec(cmd, (err) => {
|
|
5862
5788
|
if (err) console.warn(` Could not open browser: ${err.message}`);
|
|
@@ -5864,11 +5790,9 @@ async function startServer(options) {
|
|
|
5864
5790
|
}
|
|
5865
5791
|
});
|
|
5866
5792
|
process.on("SIGINT", () => {
|
|
5867
|
-
deregister(canonicalRootDir, process.pid);
|
|
5868
5793
|
void lifecycle.requestShutdown("signal");
|
|
5869
5794
|
});
|
|
5870
5795
|
process.on("SIGTERM", () => {
|
|
5871
|
-
deregister(canonicalRootDir, process.pid);
|
|
5872
5796
|
void lifecycle.requestShutdown("signal");
|
|
5873
5797
|
});
|
|
5874
5798
|
await new Promise((resolve, reject) => {
|
|
@@ -5903,23 +5827,23 @@ function findMissingSkills(workDir, config) {
|
|
|
5903
5827
|
});
|
|
5904
5828
|
}
|
|
5905
5829
|
function copyStartTemplates2(workDir) {
|
|
5906
|
-
const templateDir =
|
|
5830
|
+
const templateDir = path12.resolve(
|
|
5907
5831
|
new URL("../templates", import.meta.url).pathname
|
|
5908
5832
|
);
|
|
5909
5833
|
for (const file of ["start.sh", "start.bat"]) {
|
|
5910
|
-
const src =
|
|
5911
|
-
const dest =
|
|
5912
|
-
if (
|
|
5913
|
-
|
|
5834
|
+
const src = path12.join(templateDir, file);
|
|
5835
|
+
const dest = path12.join(workDir, file);
|
|
5836
|
+
if (fs13.existsSync(src)) {
|
|
5837
|
+
fs13.copyFileSync(src, dest);
|
|
5914
5838
|
if (file === "start.sh") {
|
|
5915
|
-
|
|
5839
|
+
fs13.chmodSync(dest, 493);
|
|
5916
5840
|
}
|
|
5917
5841
|
}
|
|
5918
5842
|
}
|
|
5919
5843
|
}
|
|
5920
5844
|
async function runCommand(directory) {
|
|
5921
|
-
const workDir = directory ?
|
|
5922
|
-
|
|
5845
|
+
const workDir = directory ? path12.resolve(directory) : process.cwd();
|
|
5846
|
+
fs13.mkdirSync(workDir, { recursive: true });
|
|
5923
5847
|
if (!configExists(workDir)) {
|
|
5924
5848
|
console.log(chalk4.blue("\n No skillpack.json found. Let's set one up.\n"));
|
|
5925
5849
|
const { name, description } = await inquirer2.prompt([
|
|
@@ -5955,16 +5879,13 @@ async function runCommand(directory) {
|
|
|
5955
5879
|
console.warn(chalk4.yellow(` Warning: Some skills could not be installed: ${err}`));
|
|
5956
5880
|
}
|
|
5957
5881
|
}
|
|
5958
|
-
await startServer({
|
|
5959
|
-
rootDir: workDir,
|
|
5960
|
-
daemonRun: process.env.DAEMON_RUN === "1"
|
|
5961
|
-
});
|
|
5882
|
+
await startServer({ rootDir: workDir, firstRun: true });
|
|
5962
5883
|
}
|
|
5963
5884
|
|
|
5964
5885
|
// src/cli.ts
|
|
5965
|
-
import
|
|
5886
|
+
import fs14 from "fs";
|
|
5966
5887
|
var packageJson = JSON.parse(
|
|
5967
|
-
|
|
5888
|
+
fs14.readFileSync(new URL("../package.json", import.meta.url), "utf-8")
|
|
5968
5889
|
);
|
|
5969
5890
|
var program = new Command();
|
|
5970
5891
|
program.name("skillpack").description("Assemble, package, and run Agent Skills packs").version(packageJson.version);
|