@cremini/skillpack 1.2.2 → 1.2.4
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 +9 -67
- package/dist/cli.js +557 -137
- package/package.json +2 -2
- package/web/js/chat.js +0 -15
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Skillpack is built for teams that want AI Agents to be deployable, trusted, and
|
|
|
23
23
|
1. Download the example
|
|
24
24
|
- [Garry Tan SkillPack](https://github.com/CreminiAI/skillpack-examples/releases/download/v.0.0.3/garry-tan.zip)
|
|
25
25
|
- [Company Deep Research SkillPack](https://github.com/FinpeakInc/downloads/releases/download/v.0.0.1/Company-Deep-Research.zip)
|
|
26
|
-
2. Unzip it and Run ./start.sh on Mac OS,
|
|
26
|
+
2. Unzip it and Run ./start.sh on Mac OS, Or double click start.bat on Windows (see below), the server starts and opens http://127.0.0.1:26313 in your browser
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
# macOS / Linux
|
|
@@ -92,11 +92,13 @@ Multiple skill names from the same source can be listed comma-separated.
|
|
|
92
92
|
|
|
93
93
|
## Zip Output
|
|
94
94
|
|
|
95
|
-
The archive produced by `zip` is intentionally
|
|
95
|
+
The archive produced by `zip` is intentionally lightweight:
|
|
96
96
|
|
|
97
97
|
```text
|
|
98
98
|
<pack-name>/
|
|
99
99
|
├── skillpack.json # Pack configuration
|
|
100
|
+
├── AGENTS.md # Optional pack policy
|
|
101
|
+
├── SOUL.md # Optional pack persona
|
|
100
102
|
├── skills/ # Installed skills
|
|
101
103
|
├── start.sh # One-click launcher for macOS / Linux
|
|
102
104
|
└── start.bat # One-click launcher for Windows
|
|
@@ -104,78 +106,18 @@ The archive produced by `zip` is intentionally minimal:
|
|
|
104
106
|
|
|
105
107
|
The start scripts use `npx @cremini/skillpack run .` so Node.js is the only prerequisite — no pre-bundled server directory is included.
|
|
106
108
|
|
|
109
|
+
If present, `AGENTS.md` and `SOUL.md` are read by SkillPack itself when a new chat session starts. SkillPack injects them into the runtime system prompt as pack-level policy and persona, without depending on the host machine's `AGENTS.md`, `.pi/SYSTEM.md`, or `APPEND_SYSTEM.md`.
|
|
110
|
+
|
|
107
111
|
## Slack/Telegram Integrations
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
**Telegram configuration**: requires `Bot Token`
|
|
113
|
+
Talk to your Agents on Slack and Telegram
|
|
111
114
|
|
|
112
|
-
###
|
|
115
|
+
### 5 mins to get Slack `App Token` and `Bot Token`
|
|
113
116
|
https://skillpack.gitbook.io/skillpack-docs/getting-started/slack-integration
|
|
114
117
|
|
|
115
|
-
1
|
|
116
|
-
2. Enable Socket Mode (Settings → Socket Mode → Enable)
|
|
117
|
-
3. Generate an App-Level Token with `connections:write` scope. This is **`App Token`**
|
|
118
|
-
4. Add Bot Token Scopes (OAuth & Permissions):
|
|
119
|
-
|
|
120
|
-
- `app_mentions:read`
|
|
121
|
-
- `channels:history`
|
|
122
|
-
- `channels:read`
|
|
123
|
-
- `chat:write`
|
|
124
|
-
- `files:read`
|
|
125
|
-
- `files:write`
|
|
126
|
-
- `groups:history`
|
|
127
|
-
- `groups:read`
|
|
128
|
-
- `im:history`
|
|
129
|
-
- `im:read`
|
|
130
|
-
- `im:write`
|
|
131
|
-
- `users:read`
|
|
132
|
-
|
|
133
|
-
5. Subscribe to Bot Events (Event Subscriptions):
|
|
134
|
-
|
|
135
|
-
- `app_mention`
|
|
136
|
-
- `message.channels`
|
|
137
|
-
- `message.groups`
|
|
138
|
-
- `message.im`
|
|
139
|
-
|
|
140
|
-
6. Enable Direct Messages (App Home):
|
|
141
|
-
Go to App Home in the left sidebar
|
|
142
|
-
Under Show Tabs, enable the Messages Tab
|
|
143
|
-
Check Allow users to send Slash commands and messages from the messages tab
|
|
144
|
-
|
|
145
|
-
7. Install the app to your workspace. Get the Bot User OAuth Token. This is **`Bot Token`**
|
|
146
|
-
8. Add the app to any channels where you want the agent to operate (it'll only see messages in channels it's added to)
|
|
147
|
-
9. On the SkillPack buit-in UI http://127.0.0.1:26313, Tap "Connect to Chat App" button and Enter the **`Bot Token`** and **`App Token`**, Save
|
|
148
|
-
|
|
149
|
-
### Telegram Setup and how to get `Bot Token`
|
|
118
|
+
### 1 min to get Telegram `Bot Token`
|
|
150
119
|
https://skillpack.gitbook.io/skillpack-docs/getting-started/telegram-integration
|
|
151
120
|
|
|
152
|
-
1. **Open Telegram** and search for the official account **`@BotFather`** (it will have a blue verified checkmark).
|
|
153
|
-
2. **Start a chat** by tapping "Start" or sending the `/start` command.
|
|
154
|
-
3. **Send the command** `/newbot` to the BotFather.
|
|
155
|
-
4. **Follow the prompts** to choose a display name and a unique username for your bot. The username must end with the word "bot" (e.g., `MyHelperBot` or `My_Helper_bot`).
|
|
156
|
-
5. **Receive the token**. Once the bot is successfully created, the BotFather will provide you with a message containing your unique API token.
|
|
157
|
-
The token will look like a long string of numbers and letters, formatted as `123456789:AABBCCddEeff.... `
|
|
158
|
-
6. On the SkillPack buit-in UI http://127.0.0.1:26313, Tap "Connect to Chat App" button and Enter the **`Bot Token`**, Save
|
|
159
|
-
|
|
160
|
-
### (Optional) Put tokens into data/config.json if you don't use Web UI
|
|
161
|
-
|
|
162
|
-
Or Once you have telegram or slack tokens, you can also configure them in `data/config.json` (created at runtime, not included in the zip):
|
|
163
|
-
The runtime supports **Slack** and **Telegram** in addition to the built-in web UI.
|
|
164
|
-
|
|
165
|
-
```json
|
|
166
|
-
{
|
|
167
|
-
"adapters": {
|
|
168
|
-
"telegram": {
|
|
169
|
-
"token": "123456:ABC-DEF..."
|
|
170
|
-
},
|
|
171
|
-
"slack": {
|
|
172
|
-
"botToken": "xoxb-...",
|
|
173
|
-
"appToken": "xapp-..."
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
121
|
---
|
|
180
122
|
|
|
181
123
|
## Example Use Cases
|
package/dist/cli.js
CHANGED
|
@@ -267,6 +267,62 @@ var init_attachment_utils = __esm({
|
|
|
267
267
|
}
|
|
268
268
|
});
|
|
269
269
|
|
|
270
|
+
// src/runtime/commands/index.ts
|
|
271
|
+
function resolveCommand(input) {
|
|
272
|
+
const key = input.split(/\s/)[0].toLowerCase();
|
|
273
|
+
return COMMAND_ALIASES[key] ?? null;
|
|
274
|
+
}
|
|
275
|
+
function getVisibleCommands() {
|
|
276
|
+
return COMMAND_REGISTRY.filter((cmd) => cmd.visibleInHelp);
|
|
277
|
+
}
|
|
278
|
+
function getTelegramBotCommands() {
|
|
279
|
+
return COMMAND_REGISTRY.filter((cmd) => cmd.visibleInHelp).map((cmd) => ({
|
|
280
|
+
command: cmd.command,
|
|
281
|
+
description: cmd.description
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
var COMMAND_REGISTRY, COMMAND_ALIASES;
|
|
285
|
+
var init_commands = __esm({
|
|
286
|
+
"src/runtime/commands/index.ts"() {
|
|
287
|
+
"use strict";
|
|
288
|
+
COMMAND_REGISTRY = [
|
|
289
|
+
{
|
|
290
|
+
command: "help",
|
|
291
|
+
description: "Show available commands, skills, and usage tips",
|
|
292
|
+
visibleInHelp: true
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
command: "clear",
|
|
296
|
+
description: "Clear current session and start fresh",
|
|
297
|
+
visibleInHelp: true
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
command: "restart",
|
|
301
|
+
description: "Restart the server process",
|
|
302
|
+
visibleInHelp: true
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
command: "shutdown",
|
|
306
|
+
description: "Shut down the server process",
|
|
307
|
+
visibleInHelp: true
|
|
308
|
+
},
|
|
309
|
+
// "new" is a hidden alias for "clear" — not shown in /help
|
|
310
|
+
{
|
|
311
|
+
command: "new",
|
|
312
|
+
description: "Start a new session (alias for /clear)",
|
|
313
|
+
visibleInHelp: false
|
|
314
|
+
}
|
|
315
|
+
];
|
|
316
|
+
COMMAND_ALIASES = {
|
|
317
|
+
"/help": "help",
|
|
318
|
+
"/clear": "clear",
|
|
319
|
+
"/new": "clear",
|
|
320
|
+
"/restart": "restart",
|
|
321
|
+
"/shutdown": "shutdown"
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
|
|
270
326
|
// src/runtime/adapters/markdown.ts
|
|
271
327
|
function unwrapMarkdownSourceBlocks(text) {
|
|
272
328
|
return text.replace(
|
|
@@ -307,6 +363,7 @@ function formatSlackInline(text) {
|
|
|
307
363
|
);
|
|
308
364
|
formatted = formatted.replace(/\*\*([^*\n]+)\*\*/g, "*$1*");
|
|
309
365
|
formatted = formatted.replace(/__([^_\n]+)__/g, "*$1*");
|
|
366
|
+
formatted = formatted.replace(/^(?:-|\*) /gm, "\u2022 ");
|
|
310
367
|
return formatted;
|
|
311
368
|
}
|
|
312
369
|
function formatTelegramInline(text) {
|
|
@@ -386,19 +443,15 @@ var telegram_exports = {};
|
|
|
386
443
|
__export(telegram_exports, {
|
|
387
444
|
TelegramAdapter: () => TelegramAdapter
|
|
388
445
|
});
|
|
389
|
-
import
|
|
446
|
+
import fs12 from "fs";
|
|
390
447
|
import TelegramBot from "node-telegram-bot-api";
|
|
391
|
-
var
|
|
448
|
+
var MAX_MESSAGE_LENGTH, ACK_REACTION, TelegramAdapter;
|
|
392
449
|
var init_telegram = __esm({
|
|
393
450
|
"src/runtime/adapters/telegram.ts"() {
|
|
394
451
|
"use strict";
|
|
395
452
|
init_markdown();
|
|
396
453
|
init_attachment_utils();
|
|
397
|
-
|
|
398
|
-
"/clear": "clear",
|
|
399
|
-
"/restart": "restart",
|
|
400
|
-
"/shutdown": "shutdown"
|
|
401
|
-
};
|
|
454
|
+
init_commands();
|
|
402
455
|
MAX_MESSAGE_LENGTH = 4096;
|
|
403
456
|
ACK_REACTION = {
|
|
404
457
|
type: "emoji",
|
|
@@ -422,11 +475,7 @@ var init_telegram = __esm({
|
|
|
422
475
|
console.error("[Telegram] Error handling message:", err);
|
|
423
476
|
});
|
|
424
477
|
});
|
|
425
|
-
await this.bot.setMyCommands(
|
|
426
|
-
{ command: "clear", description: "Clear current session and start new" },
|
|
427
|
-
{ command: "restart", description: "Restart the server process" },
|
|
428
|
-
{ command: "shutdown", description: "Shut down the server process" }
|
|
429
|
-
]);
|
|
478
|
+
await this.bot.setMyCommands(getTelegramBotCommands());
|
|
430
479
|
const me = await this.bot.getMe();
|
|
431
480
|
console.log(`[TelegramAdapter] Started as @${me.username}`);
|
|
432
481
|
}
|
|
@@ -466,7 +515,7 @@ var init_telegram = __esm({
|
|
|
466
515
|
await this.tryAckReaction(chatId, messageId);
|
|
467
516
|
if (text) {
|
|
468
517
|
const commandKey = text.split(/\s/)[0].toLowerCase();
|
|
469
|
-
const command =
|
|
518
|
+
const command = this.resolveTelegramCommand(commandKey);
|
|
470
519
|
if (command) {
|
|
471
520
|
const result = await this.agent.handleCommand(command, channelId);
|
|
472
521
|
await this.sendSafe(chatId, result.message || `/${command} executed.`);
|
|
@@ -521,6 +570,9 @@ var init_telegram = __esm({
|
|
|
521
570
|
await this.sendFileSafe(chatId, file.filePath, file.caption);
|
|
522
571
|
}
|
|
523
572
|
}
|
|
573
|
+
resolveTelegramCommand(commandKey) {
|
|
574
|
+
return resolveCommand(commandKey);
|
|
575
|
+
}
|
|
524
576
|
// -------------------------------------------------------------------------
|
|
525
577
|
// Send helpers
|
|
526
578
|
// -------------------------------------------------------------------------
|
|
@@ -697,7 +749,7 @@ var init_telegram = __esm({
|
|
|
697
749
|
async sendFileSafe(chatId, filePath, caption) {
|
|
698
750
|
if (!this.bot) return;
|
|
699
751
|
try {
|
|
700
|
-
if (!
|
|
752
|
+
if (!fs12.existsSync(filePath)) {
|
|
701
753
|
console.error(`[Telegram] File not found for sending: ${filePath}`);
|
|
702
754
|
return;
|
|
703
755
|
}
|
|
@@ -717,16 +769,18 @@ var slack_exports = {};
|
|
|
717
769
|
__export(slack_exports, {
|
|
718
770
|
SlackAdapter: () => SlackAdapter
|
|
719
771
|
});
|
|
720
|
-
import
|
|
721
|
-
import
|
|
772
|
+
import fs13 from "fs";
|
|
773
|
+
import path12 from "path";
|
|
722
774
|
import { App, LogLevel } from "@slack/bolt";
|
|
723
|
-
var INLINE_COMMANDS, SLASH_COMMANDS, MAX_MESSAGE_LENGTH2, ACK_REACTION2, SlackAdapter;
|
|
775
|
+
var INLINE_COMMANDS, SLASH_COMMANDS, MAX_MESSAGE_LENGTH2, ACK_REACTION2, PROCESSING_MESSAGE, SlackAdapter;
|
|
724
776
|
var init_slack = __esm({
|
|
725
777
|
"src/runtime/adapters/slack.ts"() {
|
|
726
778
|
"use strict";
|
|
727
779
|
init_markdown();
|
|
728
780
|
init_attachment_utils();
|
|
781
|
+
init_commands();
|
|
729
782
|
INLINE_COMMANDS = {
|
|
783
|
+
"/help": "help",
|
|
730
784
|
"/clear": "clear",
|
|
731
785
|
"/restart": "restart",
|
|
732
786
|
"/shutdown": "shutdown"
|
|
@@ -738,6 +792,7 @@ var init_slack = __esm({
|
|
|
738
792
|
};
|
|
739
793
|
MAX_MESSAGE_LENGTH2 = 3500;
|
|
740
794
|
ACK_REACTION2 = "eyes";
|
|
795
|
+
PROCESSING_MESSAGE = "_Processing..._";
|
|
741
796
|
SlackAdapter = class {
|
|
742
797
|
name = "slack";
|
|
743
798
|
app = null;
|
|
@@ -807,7 +862,7 @@ var init_slack = __esm({
|
|
|
807
862
|
console.error("[Slack] Error handling mention:", err);
|
|
808
863
|
}
|
|
809
864
|
});
|
|
810
|
-
for (const commandName of Object.keys(SLASH_COMMANDS)) {
|
|
865
|
+
for (const commandName of [...Object.keys(SLASH_COMMANDS), "/new"]) {
|
|
811
866
|
app.command(commandName, async (args) => {
|
|
812
867
|
try {
|
|
813
868
|
await this.handleSlashCommand(args);
|
|
@@ -872,7 +927,7 @@ var init_slack = __esm({
|
|
|
872
927
|
await this.sendSafe(
|
|
873
928
|
client,
|
|
874
929
|
route,
|
|
875
|
-
"Mention me with a message, or use `/clear` to reset this thread."
|
|
930
|
+
"Mention me with a message, or use `/clear` or `/new` to reset this thread."
|
|
876
931
|
);
|
|
877
932
|
return;
|
|
878
933
|
}
|
|
@@ -890,7 +945,7 @@ var init_slack = __esm({
|
|
|
890
945
|
ack
|
|
891
946
|
}) {
|
|
892
947
|
const commandName = command?.command;
|
|
893
|
-
const mapped = commandName ?
|
|
948
|
+
const mapped = commandName ? this.resolveSlashCommand(commandName) : void 0;
|
|
894
949
|
if (!this.agent || !mapped) {
|
|
895
950
|
await this.safeAck(ack, "Unsupported slash command.");
|
|
896
951
|
return;
|
|
@@ -916,6 +971,7 @@ var init_slack = __esm({
|
|
|
916
971
|
let hasError = false;
|
|
917
972
|
let errorMessage = "";
|
|
918
973
|
const pendingFiles = [];
|
|
974
|
+
const placeholder = await this.sendPlaceholderMessage(client, route);
|
|
919
975
|
const onEvent = (event) => {
|
|
920
976
|
if (event.type === "text_delta") {
|
|
921
977
|
finalText += event.delta;
|
|
@@ -943,13 +999,25 @@ var init_slack = __esm({
|
|
|
943
999
|
errorMessage = this.getErrorMessage(err);
|
|
944
1000
|
}
|
|
945
1001
|
if (hasError) {
|
|
946
|
-
await this.
|
|
1002
|
+
await this.sendOrUpdateSafe(
|
|
1003
|
+
client,
|
|
1004
|
+
route,
|
|
1005
|
+
`\u274C Error: ${errorMessage}`,
|
|
1006
|
+
placeholder
|
|
1007
|
+
);
|
|
947
1008
|
return;
|
|
948
1009
|
}
|
|
949
1010
|
if (finalText.trim()) {
|
|
950
|
-
await this.sendLongMessage(client, route, finalText);
|
|
1011
|
+
await this.sendLongMessage(client, route, finalText, placeholder);
|
|
951
1012
|
} else if (pendingFiles.length === 0) {
|
|
952
|
-
await this.
|
|
1013
|
+
await this.sendOrUpdateSafe(
|
|
1014
|
+
client,
|
|
1015
|
+
route,
|
|
1016
|
+
"(No response generated)",
|
|
1017
|
+
placeholder
|
|
1018
|
+
);
|
|
1019
|
+
} else if (placeholder) {
|
|
1020
|
+
await this.deleteMessageSafe(client, route, placeholder.ts);
|
|
953
1021
|
}
|
|
954
1022
|
for (const file of pendingFiles) {
|
|
955
1023
|
await this.sendFileSafe(client, route, file.filePath, file.caption);
|
|
@@ -961,7 +1029,7 @@ var init_slack = __esm({
|
|
|
961
1029
|
async tryHandleInlineCommand(text, channelId, client, route) {
|
|
962
1030
|
if (!this.agent) return false;
|
|
963
1031
|
const commandKey = text.split(/\s/)[0].toLowerCase();
|
|
964
|
-
const command =
|
|
1032
|
+
const command = this.resolveInlineCommand(commandKey);
|
|
965
1033
|
if (!command) return false;
|
|
966
1034
|
const result = await this.agent.handleCommand(command, channelId);
|
|
967
1035
|
await this.sendSafe(
|
|
@@ -971,6 +1039,19 @@ var init_slack = __esm({
|
|
|
971
1039
|
);
|
|
972
1040
|
return true;
|
|
973
1041
|
}
|
|
1042
|
+
resolveInlineCommand(commandKey) {
|
|
1043
|
+
const resolved = resolveCommand(commandKey);
|
|
1044
|
+
if (resolved) {
|
|
1045
|
+
return resolved;
|
|
1046
|
+
}
|
|
1047
|
+
return INLINE_COMMANDS[commandKey];
|
|
1048
|
+
}
|
|
1049
|
+
resolveSlashCommand(commandName) {
|
|
1050
|
+
if (commandName === "/new") {
|
|
1051
|
+
return "clear";
|
|
1052
|
+
}
|
|
1053
|
+
return SLASH_COMMANDS[commandName];
|
|
1054
|
+
}
|
|
974
1055
|
resolveSlashCommandTarget(payload, context) {
|
|
975
1056
|
const teamId = this.getTeamId(payload, context);
|
|
976
1057
|
const channel = payload?.channel_id;
|
|
@@ -988,7 +1069,7 @@ var init_slack = __esm({
|
|
|
988
1069
|
);
|
|
989
1070
|
if (!threadTs) {
|
|
990
1071
|
return {
|
|
991
|
-
message: "No active Skillpack thread found in this channel. Mention the bot first, or run the command inside the thread as `@bot /clear`."
|
|
1072
|
+
message: "No active Skillpack thread found in this channel. Mention the bot first, or run the command inside the thread as `@bot /clear` or `@bot /new`."
|
|
992
1073
|
};
|
|
993
1074
|
}
|
|
994
1075
|
return {
|
|
@@ -1017,33 +1098,35 @@ var init_slack = __esm({
|
|
|
1017
1098
|
return text.replace(mention, "");
|
|
1018
1099
|
}
|
|
1019
1100
|
splitMessage(text) {
|
|
1020
|
-
if (text
|
|
1101
|
+
if (this.isSlackMessageWithinLimit(text)) {
|
|
1021
1102
|
return [text];
|
|
1022
1103
|
}
|
|
1023
1104
|
const chunks = [];
|
|
1024
1105
|
let remaining = text;
|
|
1025
1106
|
while (remaining.length > 0) {
|
|
1026
|
-
if (remaining
|
|
1107
|
+
if (this.isSlackMessageWithinLimit(remaining)) {
|
|
1027
1108
|
chunks.push(remaining);
|
|
1028
1109
|
break;
|
|
1029
1110
|
}
|
|
1030
|
-
let splitAt =
|
|
1031
|
-
if (splitAt < MAX_MESSAGE_LENGTH2 * 0.5) {
|
|
1032
|
-
splitAt = remaining.lastIndexOf("\n", MAX_MESSAGE_LENGTH2);
|
|
1033
|
-
}
|
|
1034
|
-
if (splitAt < MAX_MESSAGE_LENGTH2 * 0.3) {
|
|
1035
|
-
splitAt = remaining.lastIndexOf(" ", MAX_MESSAGE_LENGTH2);
|
|
1036
|
-
}
|
|
1037
|
-
if (splitAt < 1) {
|
|
1038
|
-
splitAt = MAX_MESSAGE_LENGTH2;
|
|
1039
|
-
}
|
|
1111
|
+
let splitAt = this.findSlackSafeSplitPoint(remaining);
|
|
1040
1112
|
chunks.push(remaining.slice(0, splitAt));
|
|
1041
1113
|
remaining = remaining.slice(splitAt).trimStart();
|
|
1042
1114
|
}
|
|
1043
1115
|
return chunks;
|
|
1044
1116
|
}
|
|
1045
|
-
async sendLongMessage(client, route, text) {
|
|
1046
|
-
|
|
1117
|
+
async sendLongMessage(client, route, text, placeholder) {
|
|
1118
|
+
const chunks = this.splitMessage(text);
|
|
1119
|
+
if (chunks.length === 0) {
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
if (placeholder) {
|
|
1123
|
+
await this.updateMessageSafe(client, route, placeholder.ts, chunks[0]);
|
|
1124
|
+
for (const chunk of chunks.slice(1)) {
|
|
1125
|
+
await this.sendSafe(client, route, chunk);
|
|
1126
|
+
}
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
for (const chunk of chunks) {
|
|
1047
1130
|
await this.sendWithRetry(client, route, chunk);
|
|
1048
1131
|
}
|
|
1049
1132
|
}
|
|
@@ -1054,17 +1137,35 @@ var init_slack = __esm({
|
|
|
1054
1137
|
console.error("[Slack] Failed to send message:", err);
|
|
1055
1138
|
}
|
|
1056
1139
|
}
|
|
1140
|
+
async sendOrUpdateSafe(client, route, text, placeholder) {
|
|
1141
|
+
if (placeholder) {
|
|
1142
|
+
await this.updateMessageSafe(client, route, placeholder.ts, text);
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
await this.sendSafe(client, route, text);
|
|
1146
|
+
}
|
|
1147
|
+
async sendPlaceholderMessage(client, route) {
|
|
1148
|
+
try {
|
|
1149
|
+
return await this.sendWithRetry(client, route, PROCESSING_MESSAGE);
|
|
1150
|
+
} catch (err) {
|
|
1151
|
+
console.error("[Slack] Failed to send placeholder message:", err);
|
|
1152
|
+
return null;
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1057
1155
|
async sendWithRetry(client, route, text, maxRetries = 3) {
|
|
1058
1156
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1059
1157
|
try {
|
|
1060
|
-
await client.chat.postMessage({
|
|
1158
|
+
const response = await client.chat.postMessage({
|
|
1061
1159
|
channel: route.channel,
|
|
1062
1160
|
text: formatSlackMessage(text),
|
|
1063
1161
|
mrkdwn: true,
|
|
1064
1162
|
thread_ts: route.threadTs,
|
|
1065
1163
|
reply_broadcast: false
|
|
1066
1164
|
});
|
|
1067
|
-
|
|
1165
|
+
if (typeof response.ts !== "string") {
|
|
1166
|
+
throw new Error("Slack postMessage response missing ts");
|
|
1167
|
+
}
|
|
1168
|
+
return { ts: response.ts };
|
|
1068
1169
|
} catch (err) {
|
|
1069
1170
|
const retryAfter = this.getRetryAfterSeconds(err);
|
|
1070
1171
|
if (retryAfter && attempt < maxRetries) {
|
|
@@ -1079,6 +1180,93 @@ var init_slack = __esm({
|
|
|
1079
1180
|
throw err;
|
|
1080
1181
|
}
|
|
1081
1182
|
}
|
|
1183
|
+
throw new Error("Slack postMessage failed after retries");
|
|
1184
|
+
}
|
|
1185
|
+
async updateMessageSafe(client, route, ts, text) {
|
|
1186
|
+
try {
|
|
1187
|
+
await this.updateWithRetry(client, route, ts, text);
|
|
1188
|
+
} catch (err) {
|
|
1189
|
+
console.error("[Slack] Failed to update message:", err);
|
|
1190
|
+
await this.deleteMessageSafe(client, route, ts);
|
|
1191
|
+
await this.sendSafe(client, route, text);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
async updateWithRetry(client, route, ts, text, maxRetries = 3) {
|
|
1195
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1196
|
+
try {
|
|
1197
|
+
await client.chat.update({
|
|
1198
|
+
channel: route.channel,
|
|
1199
|
+
ts,
|
|
1200
|
+
text: formatSlackMessage(text),
|
|
1201
|
+
mrkdwn: true
|
|
1202
|
+
});
|
|
1203
|
+
return;
|
|
1204
|
+
} catch (err) {
|
|
1205
|
+
const retryAfter = this.getRetryAfterSeconds(err);
|
|
1206
|
+
if (retryAfter && attempt < maxRetries) {
|
|
1207
|
+
console.log(
|
|
1208
|
+
`[Slack] Rate limited while updating, retrying after ${retryAfter}s...`
|
|
1209
|
+
);
|
|
1210
|
+
await new Promise(
|
|
1211
|
+
(resolve) => setTimeout(resolve, retryAfter * 1e3)
|
|
1212
|
+
);
|
|
1213
|
+
continue;
|
|
1214
|
+
}
|
|
1215
|
+
throw err;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
async deleteMessageSafe(client, route, ts) {
|
|
1220
|
+
try {
|
|
1221
|
+
await client.chat.delete({
|
|
1222
|
+
channel: route.channel,
|
|
1223
|
+
ts
|
|
1224
|
+
});
|
|
1225
|
+
} catch (err) {
|
|
1226
|
+
console.error("[Slack] Failed to delete placeholder message:", err);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
isSlackMessageWithinLimit(text) {
|
|
1230
|
+
return formatSlackMessage(text).length <= MAX_MESSAGE_LENGTH2;
|
|
1231
|
+
}
|
|
1232
|
+
findSlackSafeSplitPoint(text) {
|
|
1233
|
+
const preferredBreaks = ["\n\n", "\n", " "];
|
|
1234
|
+
const minSplit = Math.floor(MAX_MESSAGE_LENGTH2 * 0.3);
|
|
1235
|
+
for (const token of preferredBreaks) {
|
|
1236
|
+
const index = this.findBestSlackSplitBefore(text, token);
|
|
1237
|
+
if (index >= minSplit) {
|
|
1238
|
+
return index;
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
let low = 1;
|
|
1242
|
+
let high = text.length;
|
|
1243
|
+
let best = Math.min(text.length, MAX_MESSAGE_LENGTH2);
|
|
1244
|
+
while (low <= high) {
|
|
1245
|
+
const mid = Math.floor((low + high) / 2);
|
|
1246
|
+
const candidate = text.slice(0, mid);
|
|
1247
|
+
if (this.isSlackMessageWithinLimit(candidate)) {
|
|
1248
|
+
best = mid;
|
|
1249
|
+
low = mid + 1;
|
|
1250
|
+
} else {
|
|
1251
|
+
high = mid - 1;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
return Math.max(1, best);
|
|
1255
|
+
}
|
|
1256
|
+
findBestSlackSplitBefore(text, token) {
|
|
1257
|
+
let fromIndex = Math.min(text.length, MAX_MESSAGE_LENGTH2);
|
|
1258
|
+
while (fromIndex > 0) {
|
|
1259
|
+
const index = text.lastIndexOf(token, fromIndex);
|
|
1260
|
+
if (index < 0) {
|
|
1261
|
+
return -1;
|
|
1262
|
+
}
|
|
1263
|
+
const splitAt = index + token.length;
|
|
1264
|
+
if (this.isSlackMessageWithinLimit(text.slice(0, splitAt))) {
|
|
1265
|
+
return splitAt;
|
|
1266
|
+
}
|
|
1267
|
+
fromIndex = index - 1;
|
|
1268
|
+
}
|
|
1269
|
+
return -1;
|
|
1082
1270
|
}
|
|
1083
1271
|
async tryAckReaction(client, event) {
|
|
1084
1272
|
try {
|
|
@@ -1196,12 +1384,12 @@ var init_slack = __esm({
|
|
|
1196
1384
|
*/
|
|
1197
1385
|
async sendFileSafe(client, route, filePath, caption) {
|
|
1198
1386
|
try {
|
|
1199
|
-
if (!
|
|
1387
|
+
if (!fs13.existsSync(filePath)) {
|
|
1200
1388
|
console.error(`[Slack] File not found for sending: ${filePath}`);
|
|
1201
1389
|
return;
|
|
1202
1390
|
}
|
|
1203
|
-
const filename =
|
|
1204
|
-
const fileContent =
|
|
1391
|
+
const filename = path12.basename(filePath);
|
|
1392
|
+
const fileContent = fs13.readFileSync(filePath);
|
|
1205
1393
|
await client.files.uploadV2({
|
|
1206
1394
|
channel_id: route.channel,
|
|
1207
1395
|
thread_ts: route.threadTs,
|
|
@@ -1787,20 +1975,120 @@ function parseSkillMd(filePath) {
|
|
|
1787
1975
|
return null;
|
|
1788
1976
|
}
|
|
1789
1977
|
const frontmatter = frontmatterMatch[1];
|
|
1790
|
-
const
|
|
1791
|
-
|
|
1792
|
-
if (!nameMatch) {
|
|
1978
|
+
const name = readFrontmatterField(frontmatter, "name");
|
|
1979
|
+
if (!name) {
|
|
1793
1980
|
return null;
|
|
1794
1981
|
}
|
|
1795
1982
|
return {
|
|
1796
|
-
name
|
|
1797
|
-
description:
|
|
1983
|
+
name,
|
|
1984
|
+
description: readFrontmatterField(frontmatter, "description") ?? "",
|
|
1798
1985
|
dir: path2.dirname(filePath)
|
|
1799
1986
|
};
|
|
1800
1987
|
} catch {
|
|
1801
1988
|
return null;
|
|
1802
1989
|
}
|
|
1803
1990
|
}
|
|
1991
|
+
function readFrontmatterField(frontmatter, field) {
|
|
1992
|
+
const lines = frontmatter.split(/\r?\n/);
|
|
1993
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
1994
|
+
const match = lines[index].match(/^([A-Za-z0-9_-]+):(?:\s*(.*))?$/);
|
|
1995
|
+
if (!match || match[1] !== field) {
|
|
1996
|
+
continue;
|
|
1997
|
+
}
|
|
1998
|
+
const rawValue = (match[2] ?? "").trim();
|
|
1999
|
+
if (isBlockScalar(rawValue)) {
|
|
2000
|
+
const [value] = readBlockScalar(lines, index + 1, rawValue);
|
|
2001
|
+
return value;
|
|
2002
|
+
}
|
|
2003
|
+
if (rawValue === "") {
|
|
2004
|
+
const [value] = readIndentedScalar(lines, index + 1);
|
|
2005
|
+
return value;
|
|
2006
|
+
}
|
|
2007
|
+
return stripWrappingQuotes(rawValue);
|
|
2008
|
+
}
|
|
2009
|
+
return null;
|
|
2010
|
+
}
|
|
2011
|
+
function isBlockScalar(value) {
|
|
2012
|
+
return /^[>|][0-9+-]*$/.test(value);
|
|
2013
|
+
}
|
|
2014
|
+
function readBlockScalar(lines, startIndex, marker) {
|
|
2015
|
+
const blockLines = [];
|
|
2016
|
+
let index = startIndex;
|
|
2017
|
+
while (index < lines.length) {
|
|
2018
|
+
const line = lines[index];
|
|
2019
|
+
if (line.trim() === "") {
|
|
2020
|
+
blockLines.push("");
|
|
2021
|
+
index += 1;
|
|
2022
|
+
continue;
|
|
2023
|
+
}
|
|
2024
|
+
if (!/^\s/.test(line)) {
|
|
2025
|
+
break;
|
|
2026
|
+
}
|
|
2027
|
+
blockLines.push(line);
|
|
2028
|
+
index += 1;
|
|
2029
|
+
}
|
|
2030
|
+
const normalized = normalizeBlockIndent(blockLines);
|
|
2031
|
+
const style = marker[0];
|
|
2032
|
+
const chomp = marker.includes("-") ? "strip" : marker.includes("+") ? "keep" : "clip";
|
|
2033
|
+
const value = style === ">" ? foldBlockScalar(normalized) : normalized.join("\n");
|
|
2034
|
+
return [applyChomp(value, chomp), index];
|
|
2035
|
+
}
|
|
2036
|
+
function readIndentedScalar(lines, startIndex) {
|
|
2037
|
+
const blockLines = [];
|
|
2038
|
+
let index = startIndex;
|
|
2039
|
+
while (index < lines.length) {
|
|
2040
|
+
const line = lines[index];
|
|
2041
|
+
if (line.trim() === "") {
|
|
2042
|
+
blockLines.push("");
|
|
2043
|
+
index += 1;
|
|
2044
|
+
continue;
|
|
2045
|
+
}
|
|
2046
|
+
if (!/^\s/.test(line)) {
|
|
2047
|
+
break;
|
|
2048
|
+
}
|
|
2049
|
+
blockLines.push(line);
|
|
2050
|
+
index += 1;
|
|
2051
|
+
}
|
|
2052
|
+
return [foldBlockScalar(normalizeBlockIndent(blockLines)), index];
|
|
2053
|
+
}
|
|
2054
|
+
function normalizeBlockIndent(lines) {
|
|
2055
|
+
const indents = lines.filter((line) => line.trim() !== "").map((line) => line.match(/^[ \t]*/)[0].length);
|
|
2056
|
+
const trimLength = indents.length > 0 ? Math.min(...indents) : 0;
|
|
2057
|
+
return lines.map((line) => line.slice(trimLength));
|
|
2058
|
+
}
|
|
2059
|
+
function foldBlockScalar(lines) {
|
|
2060
|
+
let result = "";
|
|
2061
|
+
let previousBlank = false;
|
|
2062
|
+
for (const line of lines) {
|
|
2063
|
+
const isBlank = line.trim() === "";
|
|
2064
|
+
if (isBlank) {
|
|
2065
|
+
result += "\n";
|
|
2066
|
+
previousBlank = true;
|
|
2067
|
+
continue;
|
|
2068
|
+
}
|
|
2069
|
+
if (result !== "" && !previousBlank) {
|
|
2070
|
+
result += " ";
|
|
2071
|
+
}
|
|
2072
|
+
result += line;
|
|
2073
|
+
previousBlank = false;
|
|
2074
|
+
}
|
|
2075
|
+
return result;
|
|
2076
|
+
}
|
|
2077
|
+
function applyChomp(value, mode) {
|
|
2078
|
+
if (mode === "keep") {
|
|
2079
|
+
return value;
|
|
2080
|
+
}
|
|
2081
|
+
if (mode === "strip") {
|
|
2082
|
+
return value.replace(/\n+$/g, "");
|
|
2083
|
+
}
|
|
2084
|
+
return value.replace(/\n*$/g, "");
|
|
2085
|
+
}
|
|
2086
|
+
function stripWrappingQuotes(value) {
|
|
2087
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
2088
|
+
return value.slice(1, -1);
|
|
2089
|
+
}
|
|
2090
|
+
return value;
|
|
2091
|
+
}
|
|
1804
2092
|
function syncSkillDescriptions(workDir, config) {
|
|
1805
2093
|
const descriptionByName = /* @__PURE__ */ new Map();
|
|
1806
2094
|
for (const skill of scanInstalledSkills(workDir)) {
|
|
@@ -1880,6 +2168,12 @@ async function zipCommand(workDir) {
|
|
|
1880
2168
|
archive.file(getPackPath(workDir), {
|
|
1881
2169
|
name: `${prefix}/${PACK_FILE}`
|
|
1882
2170
|
});
|
|
2171
|
+
for (const file of ["AGENTS.md", "SOUL.md"]) {
|
|
2172
|
+
const filePath = path3.join(workDir, file);
|
|
2173
|
+
if (fs3.existsSync(filePath)) {
|
|
2174
|
+
archive.file(filePath, { name: `${prefix}/${file}` });
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
1883
2177
|
const skillsDir = path3.join(workDir, "skills");
|
|
1884
2178
|
if (fs3.existsSync(skillsDir)) {
|
|
1885
2179
|
archive.directory(skillsDir, `${prefix}/skills`);
|
|
@@ -2136,15 +2430,15 @@ async function interactiveCreate(workDir) {
|
|
|
2136
2430
|
}
|
|
2137
2431
|
|
|
2138
2432
|
// src/commands/run.ts
|
|
2139
|
-
import
|
|
2140
|
-
import
|
|
2433
|
+
import path14 from "path";
|
|
2434
|
+
import fs15 from "fs";
|
|
2141
2435
|
import inquirer2 from "inquirer";
|
|
2142
2436
|
import chalk4 from "chalk";
|
|
2143
2437
|
|
|
2144
2438
|
// src/runtime/server.ts
|
|
2145
2439
|
import express from "express";
|
|
2146
|
-
import
|
|
2147
|
-
import
|
|
2440
|
+
import path13 from "path";
|
|
2441
|
+
import fs14 from "fs";
|
|
2148
2442
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2149
2443
|
import { createServer } from "http";
|
|
2150
2444
|
import { exec } from "child_process";
|
|
@@ -2152,8 +2446,8 @@ import { exec } from "child_process";
|
|
|
2152
2446
|
// src/runtime/agent.ts
|
|
2153
2447
|
init_config();
|
|
2154
2448
|
init_attachment_utils();
|
|
2155
|
-
import
|
|
2156
|
-
import
|
|
2449
|
+
import path9 from "path";
|
|
2450
|
+
import fs9 from "fs";
|
|
2157
2451
|
import { fileURLToPath } from "url";
|
|
2158
2452
|
import {
|
|
2159
2453
|
AuthStorage,
|
|
@@ -5009,6 +5303,67 @@ ${lines.join("\n")}`
|
|
|
5009
5303
|
};
|
|
5010
5304
|
}
|
|
5011
5305
|
|
|
5306
|
+
// src/runtime/commands/help-command.ts
|
|
5307
|
+
init_commands();
|
|
5308
|
+
import fs8 from "fs";
|
|
5309
|
+
import path8 from "path";
|
|
5310
|
+
function buildHelpMessage(rootDir) {
|
|
5311
|
+
const sections = [];
|
|
5312
|
+
const commands = getVisibleCommands();
|
|
5313
|
+
const commandLines = commands.map(
|
|
5314
|
+
(cmd) => `- \`/${cmd.command}\` \u2014 ${cmd.description}`
|
|
5315
|
+
);
|
|
5316
|
+
sections.push(`\u{1F4CB} **Available Commands**
|
|
5317
|
+
|
|
5318
|
+
${commandLines.join("\n")}`);
|
|
5319
|
+
const configPath = path8.resolve(rootDir, "skillpack.json");
|
|
5320
|
+
const skills = readInstalledSkills(configPath);
|
|
5321
|
+
if (skills.length > 0) {
|
|
5322
|
+
const skillLines = skills.map(
|
|
5323
|
+
(skill) => `- **${skill.name}**${skill.description ? ` \u2014 ${skill.description}` : ""}`
|
|
5324
|
+
);
|
|
5325
|
+
sections.push(
|
|
5326
|
+
`\u{1F9E9} **Installed Skills** (${skills.length})
|
|
5327
|
+
|
|
5328
|
+
${skillLines.join("\n")}`
|
|
5329
|
+
);
|
|
5330
|
+
} else {
|
|
5331
|
+
sections.push("\u{1F9E9} **Installed Skills**\nNo skills installed.");
|
|
5332
|
+
}
|
|
5333
|
+
sections.push(
|
|
5334
|
+
[
|
|
5335
|
+
"\u23F0 **Scheduled Tasks**",
|
|
5336
|
+
"",
|
|
5337
|
+
"You can set up recurring tasks using natural language. For example:",
|
|
5338
|
+
"",
|
|
5339
|
+
'- "Send me a daily market briefing every morning at 9 AM"',
|
|
5340
|
+
`- "Summarize this week's trading data every Friday at 6 PM"`,
|
|
5341
|
+
'- "Check for new announcements every 30 minutes"',
|
|
5342
|
+
"",
|
|
5343
|
+
"I will handle the cron scheduling automatically."
|
|
5344
|
+
].join("\n")
|
|
5345
|
+
);
|
|
5346
|
+
return sections.join("\n\n");
|
|
5347
|
+
}
|
|
5348
|
+
function handleHelpCommand(rootDir) {
|
|
5349
|
+
return {
|
|
5350
|
+
success: true,
|
|
5351
|
+
message: buildHelpMessage(rootDir)
|
|
5352
|
+
};
|
|
5353
|
+
}
|
|
5354
|
+
function readInstalledSkills(configPath) {
|
|
5355
|
+
if (!fs8.existsSync(configPath)) {
|
|
5356
|
+
return [];
|
|
5357
|
+
}
|
|
5358
|
+
try {
|
|
5359
|
+
const raw = fs8.readFileSync(configPath, "utf-8");
|
|
5360
|
+
const config = JSON.parse(raw);
|
|
5361
|
+
return Array.isArray(config.skills) ? config.skills : [];
|
|
5362
|
+
} catch {
|
|
5363
|
+
return [];
|
|
5364
|
+
}
|
|
5365
|
+
}
|
|
5366
|
+
|
|
5012
5367
|
// src/runtime/agent.ts
|
|
5013
5368
|
var DEBUG = true;
|
|
5014
5369
|
var log = (...args) => DEBUG && console.log(...args);
|
|
@@ -5018,25 +5373,27 @@ var BUILTIN_SKILL_CREATOR_DESCRIPTION = "Create new skills, modify and improve e
|
|
|
5018
5373
|
var BUILTIN_SKILL_CREATOR_TEMPLATE_DIR = fileURLToPath(
|
|
5019
5374
|
new URL("../templates/builtin-skills/skill-creator", import.meta.url)
|
|
5020
5375
|
);
|
|
5376
|
+
var PACK_AGENTS_FILE = "AGENTS.md";
|
|
5377
|
+
var PACK_SOUL_FILE = "SOUL.md";
|
|
5021
5378
|
function materializeBuiltinSkillCreator(rootDir, skillsPath) {
|
|
5022
|
-
if (!
|
|
5379
|
+
if (!fs9.existsSync(BUILTIN_SKILL_CREATOR_TEMPLATE_DIR)) {
|
|
5023
5380
|
log(
|
|
5024
5381
|
`[PackAgent] Built-in skill-creator template missing: ${BUILTIN_SKILL_CREATOR_TEMPLATE_DIR}`
|
|
5025
5382
|
);
|
|
5026
5383
|
return null;
|
|
5027
5384
|
}
|
|
5028
|
-
const packConfigPath =
|
|
5029
|
-
const skillDir =
|
|
5030
|
-
const skillPath =
|
|
5385
|
+
const packConfigPath = path9.resolve(rootDir, "skillpack.json");
|
|
5386
|
+
const skillDir = path9.resolve(skillsPath, BUILTIN_SKILL_CREATOR_NAME);
|
|
5387
|
+
const skillPath = path9.join(skillDir, "SKILL.md");
|
|
5031
5388
|
const renderTemplate = (content) => content.replaceAll("{{SKILLS_PATH}}", skillsPath).replaceAll("{{PACK_CONFIG_PATH}}", packConfigPath);
|
|
5032
5389
|
const copyDir = (srcDir, destDir) => {
|
|
5033
|
-
|
|
5034
|
-
for (const entry of
|
|
5390
|
+
fs9.mkdirSync(destDir, { recursive: true });
|
|
5391
|
+
for (const entry of fs9.readdirSync(srcDir, { withFileTypes: true })) {
|
|
5035
5392
|
if (entry.name === ".DS_Store") {
|
|
5036
5393
|
continue;
|
|
5037
5394
|
}
|
|
5038
|
-
const srcPath =
|
|
5039
|
-
const destPath =
|
|
5395
|
+
const srcPath = path9.join(srcDir, entry.name);
|
|
5396
|
+
const destPath = path9.join(destDir, entry.name);
|
|
5040
5397
|
if (entry.isDirectory()) {
|
|
5041
5398
|
copyDir(srcPath, destPath);
|
|
5042
5399
|
continue;
|
|
@@ -5045,17 +5402,17 @@ function materializeBuiltinSkillCreator(rootDir, skillsPath) {
|
|
|
5045
5402
|
continue;
|
|
5046
5403
|
}
|
|
5047
5404
|
if (entry.name.endsWith(".md") || entry.name.endsWith(".py")) {
|
|
5048
|
-
const content =
|
|
5049
|
-
|
|
5405
|
+
const content = fs9.readFileSync(srcPath, "utf-8");
|
|
5406
|
+
fs9.writeFileSync(destPath, renderTemplate(content), "utf-8");
|
|
5050
5407
|
continue;
|
|
5051
5408
|
}
|
|
5052
|
-
|
|
5409
|
+
fs9.copyFileSync(srcPath, destPath);
|
|
5053
5410
|
}
|
|
5054
5411
|
};
|
|
5055
|
-
if (!
|
|
5412
|
+
if (!fs9.existsSync(skillDir)) {
|
|
5056
5413
|
copyDir(BUILTIN_SKILL_CREATOR_TEMPLATE_DIR, skillDir);
|
|
5057
5414
|
}
|
|
5058
|
-
if (!
|
|
5415
|
+
if (!fs9.existsSync(skillPath)) {
|
|
5059
5416
|
log(
|
|
5060
5417
|
`[PackAgent] Materialized built-in skill-creator but SKILL.md is missing: ${skillPath}`
|
|
5061
5418
|
);
|
|
@@ -5082,6 +5439,57 @@ function overrideBuiltinSkillCreator(base, materializedSkill) {
|
|
|
5082
5439
|
diagnostics: base.diagnostics
|
|
5083
5440
|
};
|
|
5084
5441
|
}
|
|
5442
|
+
function readOptionalPackPromptFile(filePath) {
|
|
5443
|
+
if (!fs9.existsSync(filePath)) {
|
|
5444
|
+
return void 0;
|
|
5445
|
+
}
|
|
5446
|
+
try {
|
|
5447
|
+
const content = fs9.readFileSync(filePath, "utf-8").trim();
|
|
5448
|
+
return content.length > 0 ? content : void 0;
|
|
5449
|
+
} catch (error) {
|
|
5450
|
+
console.warn(`[PackAgent] Warning: Could not read ${filePath}:`, error);
|
|
5451
|
+
return void 0;
|
|
5452
|
+
}
|
|
5453
|
+
}
|
|
5454
|
+
function buildPackPromptBlock(rootDir) {
|
|
5455
|
+
const agentsPath = path9.resolve(rootDir, PACK_AGENTS_FILE);
|
|
5456
|
+
const soulPath = path9.resolve(rootDir, PACK_SOUL_FILE);
|
|
5457
|
+
const agentsContent = readOptionalPackPromptFile(agentsPath);
|
|
5458
|
+
const soulContent = readOptionalPackPromptFile(soulPath);
|
|
5459
|
+
if (!agentsContent && !soulContent) {
|
|
5460
|
+
return {
|
|
5461
|
+
agentsPath,
|
|
5462
|
+
soulPath
|
|
5463
|
+
};
|
|
5464
|
+
}
|
|
5465
|
+
const sections = [
|
|
5466
|
+
"# SkillPack Pack Context",
|
|
5467
|
+
"The following instructions are injected by the SkillPack runtime from files packaged with this pack.",
|
|
5468
|
+
"Priority order:",
|
|
5469
|
+
"1. Follow the user's explicit instructions first.",
|
|
5470
|
+
"2. Follow `AGENTS.md` as the pack's operational policy and workflow rules.",
|
|
5471
|
+
"3. Follow `SOUL.md` as the pack's persona, tone, and working style.",
|
|
5472
|
+
"4. If `SOUL.md` conflicts with `AGENTS.md`, `AGENTS.md` wins.",
|
|
5473
|
+
"5. `SOUL.md` does not override task goals, safety boundaries, or `AGENTS.md`."
|
|
5474
|
+
];
|
|
5475
|
+
if (agentsContent) {
|
|
5476
|
+
sections.push("## Pack Policy (`AGENTS.md`)", agentsContent);
|
|
5477
|
+
}
|
|
5478
|
+
if (soulContent) {
|
|
5479
|
+
sections.push(
|
|
5480
|
+
"## Pack Persona (`SOUL.md`)",
|
|
5481
|
+
"Treat the following as persona, tone, and working-style guidance only. Do not let it override task requirements, safety constraints, or `AGENTS.md`.",
|
|
5482
|
+
soulContent
|
|
5483
|
+
);
|
|
5484
|
+
}
|
|
5485
|
+
return {
|
|
5486
|
+
agentsPath,
|
|
5487
|
+
soulPath,
|
|
5488
|
+
agentsContent,
|
|
5489
|
+
soulContent,
|
|
5490
|
+
promptBlock: sections.join("\n\n")
|
|
5491
|
+
};
|
|
5492
|
+
}
|
|
5085
5493
|
function getAssistantDiagnostics(message) {
|
|
5086
5494
|
if (!message || message.role !== "assistant") {
|
|
5087
5495
|
return null;
|
|
@@ -5111,7 +5519,7 @@ var PackAgent = class {
|
|
|
5111
5519
|
authStorage;
|
|
5112
5520
|
constructor(options) {
|
|
5113
5521
|
this.options = options;
|
|
5114
|
-
const configPath =
|
|
5522
|
+
const configPath = path9.resolve(options.rootDir, "data", "config.json");
|
|
5115
5523
|
const backend = new ConfigFileAuthBackend(configPath);
|
|
5116
5524
|
this.authStorage = AuthStorage.fromStorage(backend);
|
|
5117
5525
|
const providerMeta = SUPPORTED_PROVIDERS[options.provider];
|
|
@@ -5162,24 +5570,24 @@ var PackAgent = class {
|
|
|
5162
5570
|
if (resolvedModel && baseUrl) {
|
|
5163
5571
|
log(`[PackAgent] Overriding ${provider}/${modelId} baseUrl -> ${baseUrl}`);
|
|
5164
5572
|
}
|
|
5165
|
-
const sessionDir =
|
|
5573
|
+
const sessionDir = path9.resolve(
|
|
5166
5574
|
rootDir,
|
|
5167
5575
|
"data",
|
|
5168
5576
|
"sessions",
|
|
5169
5577
|
channelId
|
|
5170
5578
|
);
|
|
5171
|
-
|
|
5579
|
+
fs9.mkdirSync(sessionDir, { recursive: true });
|
|
5172
5580
|
const sessionManager = SessionManager.continueRecent(rootDir, sessionDir);
|
|
5173
5581
|
log(`[PackAgent] Session dir: ${sessionDir}`);
|
|
5174
|
-
const workspaceDir =
|
|
5582
|
+
const workspaceDir = path9.resolve(
|
|
5175
5583
|
rootDir,
|
|
5176
5584
|
"data",
|
|
5177
5585
|
"workspaces",
|
|
5178
5586
|
channelId
|
|
5179
5587
|
);
|
|
5180
|
-
|
|
5588
|
+
fs9.mkdirSync(workspaceDir, { recursive: true });
|
|
5181
5589
|
log(`[PackAgent] Workspace dir: ${workspaceDir}`);
|
|
5182
|
-
const skillsPath =
|
|
5590
|
+
const skillsPath = path9.resolve(rootDir, "skills");
|
|
5183
5591
|
log(`[PackAgent] Loading skills from: ${skillsPath}`);
|
|
5184
5592
|
const materializedSkillCreator = materializeBuiltinSkillCreator(
|
|
5185
5593
|
rootDir,
|
|
@@ -5190,10 +5598,27 @@ var PackAgent = class {
|
|
|
5190
5598
|
`[PackAgent] Materialized built-in skill-creator to: ${materializedSkillCreator.filePath}`
|
|
5191
5599
|
);
|
|
5192
5600
|
}
|
|
5601
|
+
const packPromptFiles = buildPackPromptBlock(rootDir);
|
|
5602
|
+
if (packPromptFiles.agentsContent) {
|
|
5603
|
+
log(`[PackAgent] Loaded pack policy from: ${packPromptFiles.agentsPath}`);
|
|
5604
|
+
} else {
|
|
5605
|
+
log(`[PackAgent] No pack policy file found at: ${packPromptFiles.agentsPath}`);
|
|
5606
|
+
}
|
|
5607
|
+
if (packPromptFiles.soulContent) {
|
|
5608
|
+
log(`[PackAgent] Loaded pack persona from: ${packPromptFiles.soulPath}`);
|
|
5609
|
+
} else {
|
|
5610
|
+
log(`[PackAgent] No pack persona file found at: ${packPromptFiles.soulPath}`);
|
|
5611
|
+
}
|
|
5612
|
+
log(
|
|
5613
|
+
`[PackAgent] Pack prompt injection: ${packPromptFiles.promptBlock ? "enabled" : "disabled"}`
|
|
5614
|
+
);
|
|
5193
5615
|
const resourceLoader = new DefaultResourceLoader({
|
|
5194
5616
|
cwd: rootDir,
|
|
5195
5617
|
additionalSkillPaths: [skillsPath],
|
|
5196
|
-
skillsOverride: (base) => overrideBuiltinSkillCreator(base, materializedSkillCreator)
|
|
5618
|
+
skillsOverride: (base) => overrideBuiltinSkillCreator(base, materializedSkillCreator),
|
|
5619
|
+
agentsFilesOverride: () => ({ agentsFiles: [] }),
|
|
5620
|
+
systemPromptOverride: () => void 0,
|
|
5621
|
+
appendSystemPromptOverride: () => packPromptFiles.promptBlock ? [packPromptFiles.promptBlock] : []
|
|
5197
5622
|
});
|
|
5198
5623
|
await resourceLoader.reload();
|
|
5199
5624
|
const tools = createCodingTools(workspaceDir);
|
|
@@ -5353,6 +5778,8 @@ ${text}`;
|
|
|
5353
5778
|
}
|
|
5354
5779
|
async handleCommand(command, channelId) {
|
|
5355
5780
|
switch (command) {
|
|
5781
|
+
case "help":
|
|
5782
|
+
return handleHelpCommand(this.options.rootDir);
|
|
5356
5783
|
case "new":
|
|
5357
5784
|
case "clear": {
|
|
5358
5785
|
const cs = this.channels.get(channelId);
|
|
@@ -5361,9 +5788,9 @@ ${text}`;
|
|
|
5361
5788
|
this.channels.delete(channelId);
|
|
5362
5789
|
}
|
|
5363
5790
|
const { rootDir } = this.options;
|
|
5364
|
-
const sessionDir =
|
|
5365
|
-
if (
|
|
5366
|
-
|
|
5791
|
+
const sessionDir = path9.resolve(rootDir, "data", "sessions", channelId);
|
|
5792
|
+
if (fs9.existsSync(sessionDir)) {
|
|
5793
|
+
fs9.rmSync(sessionDir, { recursive: true, force: true });
|
|
5367
5794
|
log(`[PackAgent] Cleared session dir: ${sessionDir}`);
|
|
5368
5795
|
}
|
|
5369
5796
|
return {
|
|
@@ -5412,22 +5839,20 @@ ${text}`;
|
|
|
5412
5839
|
|
|
5413
5840
|
// src/runtime/adapters/web.ts
|
|
5414
5841
|
init_config();
|
|
5415
|
-
|
|
5416
|
-
import
|
|
5842
|
+
init_commands();
|
|
5843
|
+
import fs10 from "fs";
|
|
5844
|
+
import path10 from "path";
|
|
5417
5845
|
import { WebSocketServer } from "ws";
|
|
5418
5846
|
function getPackConfig(rootDir) {
|
|
5419
|
-
const raw =
|
|
5847
|
+
const raw = fs10.readFileSync(path10.join(rootDir, "skillpack.json"), "utf-8");
|
|
5420
5848
|
return JSON.parse(raw);
|
|
5421
5849
|
}
|
|
5422
|
-
var COMMANDS = {
|
|
5423
|
-
"/new": "new",
|
|
5424
|
-
"/clear": "clear",
|
|
5425
|
-
"/restart": "restart",
|
|
5426
|
-
"/shutdown": "shutdown"
|
|
5427
|
-
};
|
|
5428
5850
|
function parseCommand(text) {
|
|
5429
|
-
|
|
5430
|
-
|
|
5851
|
+
return resolveCommand(text.trim().toLowerCase());
|
|
5852
|
+
}
|
|
5853
|
+
function sendWsEvent(ws, event) {
|
|
5854
|
+
if (ws.readyState !== ws.OPEN) return;
|
|
5855
|
+
ws.send(JSON.stringify(event));
|
|
5431
5856
|
}
|
|
5432
5857
|
function getRuntimeConfigSignature(config) {
|
|
5433
5858
|
return JSON.stringify({
|
|
@@ -5568,23 +5993,23 @@ var WebAdapter = class {
|
|
|
5568
5993
|
res.status(400).json({ error: "Missing 'path' query parameter" });
|
|
5569
5994
|
return;
|
|
5570
5995
|
}
|
|
5571
|
-
const resolvedPath =
|
|
5572
|
-
const dataDir =
|
|
5996
|
+
const resolvedPath = path10.resolve(filePath);
|
|
5997
|
+
const dataDir = path10.resolve(rootDir, "data");
|
|
5573
5998
|
if (!resolvedPath.startsWith(dataDir)) {
|
|
5574
5999
|
res.status(403).json({ error: "Access denied" });
|
|
5575
6000
|
return;
|
|
5576
6001
|
}
|
|
5577
|
-
if (!
|
|
6002
|
+
if (!fs10.existsSync(resolvedPath)) {
|
|
5578
6003
|
res.status(404).json({ error: "File not found" });
|
|
5579
6004
|
return;
|
|
5580
6005
|
}
|
|
5581
|
-
const filename =
|
|
6006
|
+
const filename = path10.basename(resolvedPath);
|
|
5582
6007
|
res.setHeader("Content-Type", "application/octet-stream");
|
|
5583
6008
|
res.setHeader(
|
|
5584
6009
|
"Content-Disposition",
|
|
5585
6010
|
`attachment; filename="${filename}"`
|
|
5586
6011
|
);
|
|
5587
|
-
|
|
6012
|
+
fs10.createReadStream(resolvedPath).pipe(res);
|
|
5588
6013
|
});
|
|
5589
6014
|
const getScheduler = () => {
|
|
5590
6015
|
const schedulerAdapter = ctx.adapterMap?.get("scheduler");
|
|
@@ -5705,21 +6130,14 @@ var WebAdapter = class {
|
|
|
5705
6130
|
const command = parseCommand(text);
|
|
5706
6131
|
if (command) {
|
|
5707
6132
|
const result2 = await agent.handleCommand(command, channelId);
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
type: "command_result",
|
|
5711
|
-
command,
|
|
5712
|
-
...result2
|
|
5713
|
-
})
|
|
5714
|
-
);
|
|
5715
|
-
if (command === "clear" || command === "new") {
|
|
5716
|
-
ws.send(JSON.stringify({ done: true }));
|
|
6133
|
+
if (result2.message) {
|
|
6134
|
+
sendWsEvent(ws, { type: "text_delta", delta: result2.message });
|
|
5717
6135
|
}
|
|
6136
|
+
ws.send(JSON.stringify({ done: true }));
|
|
5718
6137
|
return;
|
|
5719
6138
|
}
|
|
5720
6139
|
const onEvent = (event) => {
|
|
5721
|
-
|
|
5722
|
-
ws.send(JSON.stringify(event));
|
|
6140
|
+
sendWsEvent(ws, event);
|
|
5723
6141
|
};
|
|
5724
6142
|
const result = await agent.handleMessage("web", channelId, text, onEvent);
|
|
5725
6143
|
if (result.errorMessage) {
|
|
@@ -5813,28 +6231,28 @@ var Lifecycle = class {
|
|
|
5813
6231
|
|
|
5814
6232
|
// src/runtime/registry.ts
|
|
5815
6233
|
import crypto from "crypto";
|
|
5816
|
-
import
|
|
6234
|
+
import fs11 from "fs";
|
|
5817
6235
|
import os from "os";
|
|
5818
|
-
import
|
|
5819
|
-
var SKILLPACK_HOME =
|
|
5820
|
-
var LEGACY_REGISTRY_FILE =
|
|
5821
|
-
var REGISTRY_DIR =
|
|
6236
|
+
import path11 from "path";
|
|
6237
|
+
var SKILLPACK_HOME = path11.join(os.homedir(), ".skillpack");
|
|
6238
|
+
var LEGACY_REGISTRY_FILE = path11.join(SKILLPACK_HOME, "registry.json");
|
|
6239
|
+
var REGISTRY_DIR = path11.join(SKILLPACK_HOME, "registry.d");
|
|
5822
6240
|
var migrationChecked = false;
|
|
5823
6241
|
function ensureHomeDir() {
|
|
5824
|
-
if (!
|
|
5825
|
-
|
|
6242
|
+
if (!fs11.existsSync(SKILLPACK_HOME)) {
|
|
6243
|
+
fs11.mkdirSync(SKILLPACK_HOME, { recursive: true });
|
|
5826
6244
|
}
|
|
5827
6245
|
}
|
|
5828
6246
|
function ensureRegistryDir() {
|
|
5829
6247
|
ensureHomeDir();
|
|
5830
|
-
if (!
|
|
5831
|
-
|
|
6248
|
+
if (!fs11.existsSync(REGISTRY_DIR)) {
|
|
6249
|
+
fs11.mkdirSync(REGISTRY_DIR, { recursive: true });
|
|
5832
6250
|
}
|
|
5833
6251
|
}
|
|
5834
6252
|
function canonicalizeDir(dir) {
|
|
5835
|
-
const resolved =
|
|
6253
|
+
const resolved = path11.resolve(dir);
|
|
5836
6254
|
try {
|
|
5837
|
-
return
|
|
6255
|
+
return fs11.realpathSync(resolved);
|
|
5838
6256
|
} catch {
|
|
5839
6257
|
return resolved;
|
|
5840
6258
|
}
|
|
@@ -5843,7 +6261,7 @@ function hashDir(dir) {
|
|
|
5843
6261
|
return crypto.createHash("md5").update(canonicalizeDir(dir)).digest("hex");
|
|
5844
6262
|
}
|
|
5845
6263
|
function getEntryPathForCanonicalDir(dir) {
|
|
5846
|
-
return
|
|
6264
|
+
return path11.join(REGISTRY_DIR, `${hashDir(dir)}.json`);
|
|
5847
6265
|
}
|
|
5848
6266
|
function getEntryPath(dir) {
|
|
5849
6267
|
ensureRegistryReady();
|
|
@@ -5851,11 +6269,11 @@ function getEntryPath(dir) {
|
|
|
5851
6269
|
}
|
|
5852
6270
|
function listEntryFiles() {
|
|
5853
6271
|
ensureRegistryReady();
|
|
5854
|
-
return
|
|
6272
|
+
return fs11.readdirSync(REGISTRY_DIR).filter((file) => file.endsWith(".json")).sort().map((file) => path11.join(REGISTRY_DIR, file));
|
|
5855
6273
|
}
|
|
5856
6274
|
function readEntryFile(filePath) {
|
|
5857
6275
|
try {
|
|
5858
|
-
const raw =
|
|
6276
|
+
const raw = fs11.readFileSync(filePath, "utf-8");
|
|
5859
6277
|
const data = JSON.parse(raw);
|
|
5860
6278
|
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") {
|
|
5861
6279
|
return null;
|
|
@@ -5888,8 +6306,8 @@ function writeEntryFile(entry) {
|
|
|
5888
6306
|
};
|
|
5889
6307
|
const entryPath = getEntryPathForCanonicalDir(normalized.dir);
|
|
5890
6308
|
const tmpPath = createTmpPath(entryPath);
|
|
5891
|
-
|
|
5892
|
-
|
|
6309
|
+
fs11.writeFileSync(tmpPath, JSON.stringify(normalized, null, 2), "utf-8");
|
|
6310
|
+
fs11.renameSync(tmpPath, entryPath);
|
|
5893
6311
|
}
|
|
5894
6312
|
function migrateLegacyRegistryIfNeeded() {
|
|
5895
6313
|
if (migrationChecked) {
|
|
@@ -5897,14 +6315,14 @@ function migrateLegacyRegistryIfNeeded() {
|
|
|
5897
6315
|
}
|
|
5898
6316
|
migrationChecked = true;
|
|
5899
6317
|
ensureRegistryDir();
|
|
5900
|
-
if (!
|
|
6318
|
+
if (!fs11.existsSync(LEGACY_REGISTRY_FILE)) {
|
|
5901
6319
|
return;
|
|
5902
6320
|
}
|
|
5903
6321
|
if (listEntryFiles().length > 0) {
|
|
5904
6322
|
return;
|
|
5905
6323
|
}
|
|
5906
6324
|
try {
|
|
5907
|
-
const raw =
|
|
6325
|
+
const raw = fs11.readFileSync(LEGACY_REGISTRY_FILE, "utf-8");
|
|
5908
6326
|
const data = JSON.parse(raw);
|
|
5909
6327
|
const packs = Array.isArray(data?.packs) ? data.packs : [];
|
|
5910
6328
|
for (const pack of packs) {
|
|
@@ -5917,7 +6335,7 @@ function migrateLegacyRegistryIfNeeded() {
|
|
|
5917
6335
|
} catch {
|
|
5918
6336
|
}
|
|
5919
6337
|
}
|
|
5920
|
-
|
|
6338
|
+
fs11.renameSync(LEGACY_REGISTRY_FILE, `${LEGACY_REGISTRY_FILE}.legacy`);
|
|
5921
6339
|
} catch (err) {
|
|
5922
6340
|
console.warn(" [Registry] Failed to migrate legacy registry.json:", err);
|
|
5923
6341
|
}
|
|
@@ -5970,7 +6388,7 @@ function deregister(dir, pid) {
|
|
|
5970
6388
|
}
|
|
5971
6389
|
|
|
5972
6390
|
// src/runtime/server.ts
|
|
5973
|
-
var __dirname =
|
|
6391
|
+
var __dirname = path13.dirname(fileURLToPath2(import.meta.url));
|
|
5974
6392
|
async function startServer(options) {
|
|
5975
6393
|
const {
|
|
5976
6394
|
rootDir,
|
|
@@ -5985,8 +6403,8 @@ async function startServer(options) {
|
|
|
5985
6403
|
const packConfig = loadConfig(canonicalRootDir);
|
|
5986
6404
|
const baseUrl = dataConfig.baseUrl?.trim() || void 0;
|
|
5987
6405
|
const modelId = SUPPORTED_PROVIDERS[provider]?.defaultModelId ?? SUPPORTED_PROVIDERS.openai.defaultModelId;
|
|
5988
|
-
const packageRoot =
|
|
5989
|
-
const webDir =
|
|
6406
|
+
const packageRoot = path13.resolve(__dirname, "..");
|
|
6407
|
+
const webDir = fs14.existsSync(path13.join(rootDir, "web")) ? path13.join(rootDir, "web") : path13.join(packageRoot, "web");
|
|
5990
6408
|
const app = express();
|
|
5991
6409
|
app.use(express.json());
|
|
5992
6410
|
app.use(express.static(webDir));
|
|
@@ -6154,23 +6572,23 @@ function findMissingSkills(workDir, config) {
|
|
|
6154
6572
|
});
|
|
6155
6573
|
}
|
|
6156
6574
|
function copyStartTemplates2(workDir) {
|
|
6157
|
-
const templateDir =
|
|
6575
|
+
const templateDir = path14.resolve(
|
|
6158
6576
|
new URL("../templates", import.meta.url).pathname
|
|
6159
6577
|
);
|
|
6160
6578
|
for (const file of ["start.sh", "start.bat"]) {
|
|
6161
|
-
const src =
|
|
6162
|
-
const dest =
|
|
6163
|
-
if (
|
|
6164
|
-
|
|
6579
|
+
const src = path14.join(templateDir, file);
|
|
6580
|
+
const dest = path14.join(workDir, file);
|
|
6581
|
+
if (fs15.existsSync(src)) {
|
|
6582
|
+
fs15.copyFileSync(src, dest);
|
|
6165
6583
|
if (file === "start.sh") {
|
|
6166
|
-
|
|
6584
|
+
fs15.chmodSync(dest, 493);
|
|
6167
6585
|
}
|
|
6168
6586
|
}
|
|
6169
6587
|
}
|
|
6170
6588
|
}
|
|
6171
6589
|
async function runCommand(directory) {
|
|
6172
|
-
const workDir = directory ?
|
|
6173
|
-
|
|
6590
|
+
const workDir = directory ? path14.resolve(directory) : process.cwd();
|
|
6591
|
+
fs15.mkdirSync(workDir, { recursive: true });
|
|
6174
6592
|
if (!configExists(workDir)) {
|
|
6175
6593
|
console.log(chalk4.blue("\n No skillpack.json found. Let's set one up.\n"));
|
|
6176
6594
|
const { name, description } = await inquirer2.prompt([
|
|
@@ -6206,6 +6624,8 @@ async function runCommand(directory) {
|
|
|
6206
6624
|
console.warn(chalk4.yellow(` Warning: Some skills could not be installed: ${err}`));
|
|
6207
6625
|
}
|
|
6208
6626
|
}
|
|
6627
|
+
syncSkillDescriptions(workDir, config);
|
|
6628
|
+
saveConfig(workDir, config);
|
|
6209
6629
|
await startServer({
|
|
6210
6630
|
rootDir: workDir,
|
|
6211
6631
|
daemonRun: process.env.DAEMON_RUN === "1"
|
|
@@ -6213,9 +6633,9 @@ async function runCommand(directory) {
|
|
|
6213
6633
|
}
|
|
6214
6634
|
|
|
6215
6635
|
// src/cli.ts
|
|
6216
|
-
import
|
|
6636
|
+
import fs16 from "fs";
|
|
6217
6637
|
var packageJson = JSON.parse(
|
|
6218
|
-
|
|
6638
|
+
fs16.readFileSync(new URL("../package.json", import.meta.url), "utf-8")
|
|
6219
6639
|
);
|
|
6220
6640
|
var program = new Command();
|
|
6221
6641
|
program.name("skillpack").description("Assemble, package, and run Agent Skills packs").version(packageJson.version);
|
package/package.json
CHANGED
package/web/js/chat.js
CHANGED
|
@@ -282,21 +282,6 @@ function handleAgentEvent(event) {
|
|
|
282
282
|
hideLoadingIndicator();
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
// Handle bot command results injected by the backend WebSocket response
|
|
286
|
-
if (event.type === "command_result") {
|
|
287
|
-
const textBlock = getOrCreateTextBlock();
|
|
288
|
-
let resText = `Command \`${event.command}\` succeeded.`;
|
|
289
|
-
if (event.errorMessage) {
|
|
290
|
-
resText = `Command \`${event.command}\` failed: ${event.errorMessage}`;
|
|
291
|
-
} else if (event.result) {
|
|
292
|
-
resText = `Command \`${event.command}\` result:\n\n${event.result}`;
|
|
293
|
-
}
|
|
294
|
-
textBlock.dataset.mdContent += resText;
|
|
295
|
-
textBlock.innerHTML = renderMarkdown(textBlock.dataset.mdContent);
|
|
296
|
-
scrollToBottom();
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
285
|
switch (event.type) {
|
|
301
286
|
case "agent_start":
|
|
302
287
|
case "message_start":
|