@skilder-ai/runtime 0.9.10 → 0.9.12
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/index.js
CHANGED
|
@@ -87799,6 +87799,9 @@ function loadEnv(projectRoot2, packagePath2, quiet = false) {
|
|
|
87799
87799
|
var fs = __toESM(require("fs"), 1);
|
|
87800
87800
|
var path = __toESM(require("path"), 1);
|
|
87801
87801
|
var crypto2 = __toESM(require("crypto"), 1);
|
|
87802
|
+
function getAssetCacheDir(config2) {
|
|
87803
|
+
return config2.assetCacheDir ?? path.join(config2.workingDir, "assets");
|
|
87804
|
+
}
|
|
87802
87805
|
var SKILDER_FILE_PREFIX = "@skilder-file:/";
|
|
87803
87806
|
var SKILDER_ASSET_PREFIX = "@skilder-asset:/";
|
|
87804
87807
|
function isSkilderAssetPath(filePath) {
|
|
@@ -87835,7 +87838,7 @@ function parseAssetPath(assetPath) {
|
|
|
87835
87838
|
}
|
|
87836
87839
|
function resolveAssetCachePath(assetPath, config2) {
|
|
87837
87840
|
const { resourceId, extension } = parseAssetPath(assetPath);
|
|
87838
|
-
return path.join(config2
|
|
87841
|
+
return path.join(getAssetCacheDir(config2), `${resourceId}${extension}`);
|
|
87839
87842
|
}
|
|
87840
87843
|
async function writeAssetCache(assetPath, buffer, config2) {
|
|
87841
87844
|
const cachePath = resolveAssetCachePath(assetPath, config2);
|
|
@@ -87867,7 +87870,14 @@ function resolveFilePath(filePath, config2) {
|
|
|
87867
87870
|
return resolveAssetCachePath(filePath, config2);
|
|
87868
87871
|
}
|
|
87869
87872
|
if (filePath.startsWith(SKILDER_FILE_PREFIX)) {
|
|
87870
|
-
const
|
|
87873
|
+
const rest = filePath.slice(SKILDER_FILE_PREFIX.length);
|
|
87874
|
+
if (rest.split("/").some((seg) => seg === "..")) {
|
|
87875
|
+
throw new Error(`Path traversal detected: ${filePath}`);
|
|
87876
|
+
}
|
|
87877
|
+
const filename = path.basename(rest);
|
|
87878
|
+
if (!filename || filename === ".") {
|
|
87879
|
+
throw new Error(`Invalid skilder file path: ${filePath}`);
|
|
87880
|
+
}
|
|
87871
87881
|
const resolved = path.normalize(path.join(config2.workingDir, filename));
|
|
87872
87882
|
if (!resolved.startsWith(workingDirPrefix) && resolved !== config2.workingDir) {
|
|
87873
87883
|
throw new Error(`Path traversal detected: ${filePath}`);
|
|
@@ -87881,6 +87891,11 @@ function resolveFilePath(filePath, config2) {
|
|
|
87881
87891
|
if (normalized === config2.workingDir || normalized.startsWith(workingDirPrefix)) {
|
|
87882
87892
|
return normalized;
|
|
87883
87893
|
}
|
|
87894
|
+
const assetCacheDir = getAssetCacheDir(config2);
|
|
87895
|
+
const assetCachePrefix = assetCacheDir.endsWith(path.sep) ? assetCacheDir : assetCacheDir + path.sep;
|
|
87896
|
+
if (normalized === assetCacheDir || normalized.startsWith(assetCachePrefix)) {
|
|
87897
|
+
return normalized;
|
|
87898
|
+
}
|
|
87884
87899
|
for (const allowed of config2.allowedPaths) {
|
|
87885
87900
|
const allowedPrefix = allowed.endsWith(path.sep) ? allowed : allowed + path.sep;
|
|
87886
87901
|
if (normalized === allowed || normalized.startsWith(allowedPrefix)) {
|
|
@@ -87888,7 +87903,7 @@ function resolveFilePath(filePath, config2) {
|
|
|
87888
87903
|
}
|
|
87889
87904
|
}
|
|
87890
87905
|
throw new Error(
|
|
87891
|
-
`File path not in allowed locations: ${filePath}. Allowed: ${[config2.workingDir, ...config2.allowedPaths].join(", ")}`
|
|
87906
|
+
`File path not in allowed locations: ${filePath}. Allowed: ${[config2.workingDir, assetCacheDir, ...config2.allowedPaths].join(", ")}`
|
|
87892
87907
|
);
|
|
87893
87908
|
}
|
|
87894
87909
|
function generateSkilderPath(extension) {
|
|
@@ -110508,12 +110523,13 @@ var DefaultMCPClient = class {
|
|
|
110508
110523
|
|
|
110509
110524
|
// ../common/src/node-helpers/mcp-client.ts
|
|
110510
110525
|
async function createSkilderMCPClient(options) {
|
|
110511
|
-
const { url: url2, userKey, delegateDepth } = options;
|
|
110526
|
+
const { url: url2, userKey, delegateDepth, name: name21 = "skilder-studio" } = options;
|
|
110512
110527
|
const headers = { user_key: userKey };
|
|
110513
110528
|
if (delegateDepth != null) {
|
|
110514
110529
|
headers["x-delegate-depth"] = String(delegateDepth);
|
|
110515
110530
|
}
|
|
110516
110531
|
return createMCPClient({
|
|
110532
|
+
name: name21,
|
|
110517
110533
|
transport: {
|
|
110518
110534
|
type: "http",
|
|
110519
110535
|
url: url2,
|
|
@@ -110745,6 +110761,10 @@ function buildStreamTransport(transport) {
|
|
|
110745
110761
|
};
|
|
110746
110762
|
}
|
|
110747
110763
|
|
|
110764
|
+
// ../common/src/connection-options.ts
|
|
110765
|
+
var CONNECTED_WINDOW_HOURS = 24;
|
|
110766
|
+
var CONNECTED_WINDOW_MS = CONNECTED_WINDOW_HOURS * 60 * 60 * 1e3;
|
|
110767
|
+
|
|
110748
110768
|
// ../common/src/services/logger.service.ts
|
|
110749
110769
|
var import_pino = __toESM(require_pino(), 1);
|
|
110750
110770
|
var import_pino_pretty = __toESM(require_pino_pretty(), 1);
|
|
@@ -137449,13 +137469,17 @@ var AIProviderService = class AIProviderService2 {
|
|
|
137449
137469
|
/**
|
|
137450
137470
|
* Chat with a specific model (sync).
|
|
137451
137471
|
* Accepts config directly - caller is responsible for providing decrypted config.
|
|
137472
|
+
*
|
|
137473
|
+
* @param abortSignal Optional AbortSignal; when aborted, the underlying
|
|
137474
|
+
* provider request is cancelled (no cost / connection leak on timeout).
|
|
137452
137475
|
*/
|
|
137453
|
-
async chat(config2, provider, modelName, message, slug) {
|
|
137476
|
+
async chat(config2, provider, modelName, message, slug, abortSignal) {
|
|
137454
137477
|
const model = this.getProviderModel(provider, modelName, config2, slug);
|
|
137455
137478
|
try {
|
|
137456
137479
|
const result = await generateText({
|
|
137457
137480
|
model,
|
|
137458
|
-
messages: [{ role: "user", content: message }]
|
|
137481
|
+
messages: [{ role: "user", content: message }],
|
|
137482
|
+
abortSignal
|
|
137459
137483
|
});
|
|
137460
137484
|
return result.text;
|
|
137461
137485
|
} catch (error48) {
|
|
@@ -137776,7 +137800,8 @@ var CACHE_BUCKETS = {
|
|
|
137776
137800
|
RATE_LIMIT_KEY: "rate-limit-key",
|
|
137777
137801
|
RATE_LIMIT_IP: "rate-limit-ip",
|
|
137778
137802
|
FASTIFY_RATE_LIMIT: "fastify-rate-limit",
|
|
137779
|
-
GITHUB_RATE_LIMIT: "github-rate-limit"
|
|
137803
|
+
GITHUB_RATE_LIMIT: "github-rate-limit",
|
|
137804
|
+
COMMUNITY_SKILLS_RATE_LIMIT: "community-skills-rate-limit"
|
|
137780
137805
|
};
|
|
137781
137806
|
var CACHE_BUCKET_TTLS = {
|
|
137782
137807
|
HEARTBEAT: 30 * 1e3,
|
|
@@ -137797,8 +137822,10 @@ var CACHE_BUCKET_TTLS = {
|
|
|
137797
137822
|
// 1 hour
|
|
137798
137823
|
FASTIFY_RATE_LIMIT: 60 * 1e3,
|
|
137799
137824
|
// 1 minute
|
|
137800
|
-
GITHUB_RATE_LIMIT: 2 * 60 * 1e3
|
|
137825
|
+
GITHUB_RATE_LIMIT: 2 * 60 * 1e3,
|
|
137801
137826
|
// 2 minutes (window is 1 min, extra margin ensures NATS TTL doesn't evict before resetAt check)
|
|
137827
|
+
COMMUNITY_SKILLS_RATE_LIMIT: 2 * 60 * 1e3
|
|
137828
|
+
// 2 minutes (window is 1 min, see GITHUB_RATE_LIMIT for rationale)
|
|
137802
137829
|
};
|
|
137803
137830
|
var CACHE_SERVICE = "cache.service";
|
|
137804
137831
|
var CACHE_SERVICE_CONFIG = "cache.service.config";
|
|
@@ -137838,6 +137865,10 @@ function createCacheServiceConfig() {
|
|
|
137838
137865
|
{
|
|
137839
137866
|
name: CACHE_BUCKETS.GITHUB_RATE_LIMIT,
|
|
137840
137867
|
ttlMs: parseTTL("GITHUB_RATE_LIMIT_CACHE_TTL", CACHE_BUCKET_TTLS.GITHUB_RATE_LIMIT)
|
|
137868
|
+
},
|
|
137869
|
+
{
|
|
137870
|
+
name: CACHE_BUCKETS.COMMUNITY_SKILLS_RATE_LIMIT,
|
|
137871
|
+
ttlMs: parseTTL("COMMUNITY_SKILLS_RATE_LIMIT_CACHE_TTL", CACHE_BUCKET_TTLS.COMMUNITY_SKILLS_RATE_LIMIT)
|
|
137841
137872
|
}
|
|
137842
137873
|
]
|
|
137843
137874
|
};
|
|
@@ -138782,6 +138813,7 @@ var dgraph_resolvers_types_exports = {};
|
|
|
138782
138813
|
__export(dgraph_resolvers_types_exports, {
|
|
138783
138814
|
ActiveStatus: () => ActiveStatus,
|
|
138784
138815
|
AiProviderType: () => AiProviderType,
|
|
138816
|
+
ConversationMode: () => ConversationMode,
|
|
138785
138817
|
HatColor: () => HatColor,
|
|
138786
138818
|
InvitationStatus: () => InvitationStatus,
|
|
138787
138819
|
McpServerStatus: () => McpServerStatus,
|
|
@@ -138813,6 +138845,11 @@ var ActiveStatus = /* @__PURE__ */ ((ActiveStatus2) => {
|
|
|
138813
138845
|
ActiveStatus2["Inactive"] = "INACTIVE";
|
|
138814
138846
|
return ActiveStatus2;
|
|
138815
138847
|
})(ActiveStatus || {});
|
|
138848
|
+
var ConversationMode = /* @__PURE__ */ ((ConversationMode2) => {
|
|
138849
|
+
ConversationMode2["Manage"] = "MANAGE";
|
|
138850
|
+
ConversationMode2["Run"] = "RUN";
|
|
138851
|
+
return ConversationMode2;
|
|
138852
|
+
})(ConversationMode || {});
|
|
138816
138853
|
var HatColor = /* @__PURE__ */ ((HatColor2) => {
|
|
138817
138854
|
HatColor2["Blue"] = "BLUE";
|
|
138818
138855
|
HatColor2["Gray"] = "GRAY";
|
|
@@ -144319,6 +144356,7 @@ var FileService = class FileService2 extends LifecycleService {
|
|
|
144319
144356
|
getFileConfig() {
|
|
144320
144357
|
return {
|
|
144321
144358
|
workingDir: this.workingDir,
|
|
144359
|
+
assetCacheDir: this.getAssetCacheDir(),
|
|
144322
144360
|
allowedPaths: this.allowedPaths,
|
|
144323
144361
|
maxFileSizeMB: this.maxFileSizeMB
|
|
144324
144362
|
};
|
|
@@ -144541,7 +144579,8 @@ var DelegateService = class DelegateService2 {
|
|
|
144541
144579
|
createSkilderMCPClient({
|
|
144542
144580
|
url: runtimeUrl,
|
|
144543
144581
|
userKey,
|
|
144544
|
-
delegateDepth: currentDepth + 1
|
|
144582
|
+
delegateDepth: currentDepth + 1,
|
|
144583
|
+
name: "skilder-runtime-delegate"
|
|
144545
144584
|
}),
|
|
144546
144585
|
new Promise((_3, reject) => {
|
|
144547
144586
|
connectionTimer = setTimeout(() => reject(new Error("MCP client connection timeout")), DELEGATE_MCP_CLIENT_TIMEOUT_MS);
|
|
@@ -145382,6 +145421,17 @@ function handleGetHat(hatName, ctx) {
|
|
|
145382
145421
|
}
|
|
145383
145422
|
const hat = ctx.catalog.hats.find((h2) => h2.name === hatName);
|
|
145384
145423
|
if (!hat) {
|
|
145424
|
+
const hidden = ctx.catalog.hiddenHats?.find((h2) => h2.name === hatName);
|
|
145425
|
+
if (hidden?.reason === "no-skills") {
|
|
145426
|
+
return errorResult(
|
|
145427
|
+
`The hat "${hatName}" exists but has no skills yet, so it can't be worn. Add at least one skill to it (add-skill-to-hat), then learn it. Do not create it again.`
|
|
145428
|
+
);
|
|
145429
|
+
}
|
|
145430
|
+
if (hidden?.reason === "disabled") {
|
|
145431
|
+
return errorResult(
|
|
145432
|
+
`The hat "${hatName}" exists but is disabled, so it can't be worn. Enable it first, then learn it. Do not create it again.`
|
|
145433
|
+
);
|
|
145434
|
+
}
|
|
145385
145435
|
const availableHats = ctx.catalog.hats.map((h2) => h2.name).join(", ") || "none";
|
|
145386
145436
|
return errorResult(`Error: Hat "${hatName}" not found. Available hats: ${availableHats}`);
|
|
145387
145437
|
}
|
|
@@ -154147,24 +154197,43 @@ function rewriteWorkspacePathsInResult(result, workspaceId, workspaceDir, runtim
|
|
|
154147
154197
|
return result;
|
|
154148
154198
|
const esc2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
154149
154199
|
const workingRootName = import_path3.default.basename(import_path3.default.dirname(workspaceDir));
|
|
154150
|
-
const
|
|
154200
|
+
const absPatterns = [new RegExp(esc2(workspaceDir), "g")];
|
|
154151
154201
|
if (workingRootName) {
|
|
154152
|
-
|
|
154202
|
+
absPatterns.push(new RegExp(`(?<![\\w/.-])${esc2(workingRootName)}/${esc2(workspaceId)}`, "g"));
|
|
154153
154203
|
}
|
|
154154
154204
|
const replacement = `@skilder-file:/${runtimeId}`;
|
|
154205
|
+
const bareSkilderPattern = /@skilder-file:\/([^/"'\s]+)(?=["'\s]|$)/g;
|
|
154206
|
+
const rewriteText = (input) => {
|
|
154207
|
+
let text2 = input;
|
|
154208
|
+
for (const p2 of absPatterns)
|
|
154209
|
+
text2 = text2.replace(p2, replacement);
|
|
154210
|
+
text2 = text2.replace(bareSkilderPattern, `@skilder-file:/${runtimeId}/$1`);
|
|
154211
|
+
return text2;
|
|
154212
|
+
};
|
|
154213
|
+
const rewriteValue = (val) => {
|
|
154214
|
+
if (typeof val === "string")
|
|
154215
|
+
return rewriteText(val);
|
|
154216
|
+
if (Array.isArray(val))
|
|
154217
|
+
return val.map(rewriteValue);
|
|
154218
|
+
if (val && typeof val === "object") {
|
|
154219
|
+
return Object.fromEntries(Object.entries(val).map(([k3, v2]) => [k3, rewriteValue(v2)]));
|
|
154220
|
+
}
|
|
154221
|
+
return val;
|
|
154222
|
+
};
|
|
154155
154223
|
const rewritten = result.content.map((block) => {
|
|
154156
154224
|
if (block && block.type === "text" && typeof block.text === "string") {
|
|
154157
|
-
|
|
154158
|
-
|
|
154159
|
-
for (const p2 of patterns)
|
|
154160
|
-
text2 = text2.replace(p2, replacement);
|
|
154161
|
-
if (text2 === before)
|
|
154225
|
+
const text2 = rewriteText(block.text);
|
|
154226
|
+
if (text2 === block.text)
|
|
154162
154227
|
return block;
|
|
154163
154228
|
return { ...block, text: text2 };
|
|
154164
154229
|
}
|
|
154165
154230
|
return block;
|
|
154166
154231
|
});
|
|
154167
|
-
|
|
154232
|
+
const out = { ...result, content: rewritten };
|
|
154233
|
+
if (result.structuredContent && typeof result.structuredContent === "object") {
|
|
154234
|
+
out.structuredContent = rewriteValue(result.structuredContent);
|
|
154235
|
+
}
|
|
154236
|
+
return out;
|
|
154168
154237
|
}
|
|
154169
154238
|
function formatScriptError(stderr, exitCode) {
|
|
154170
154239
|
const lines = stderr.split("\n");
|