@hasna/skills 0.1.64 → 0.1.66
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 +33 -16
- package/bin/index.js +594 -509
- package/bin/mcp.js +277 -237
- package/bin/server.js +789 -232
- package/bin/worker.js +178 -148
- package/dist/index.d.ts +1 -1
- package/dist/index.js +419 -321
- package/dist/lib/agent-sync.d.ts +2 -2
- package/dist/lib/native-storage.d.ts +28 -0
- package/dist/lib/portable-skills.d.ts +14 -0
- package/dist/lib/registry-types.d.ts +9 -0
- package/dist/lib/run-routing.d.ts +60 -0
- package/dist/sdk/index.js +14095 -14019
- package/dist/server/app.d.ts +3 -0
- package/dist/server/store-fixtures.d.ts +6 -0
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +50 -0
- package/package.json +1 -1
package/bin/worker.js
CHANGED
|
@@ -32848,23 +32848,40 @@ function concat(chunks) {
|
|
|
32848
32848
|
return merged;
|
|
32849
32849
|
}
|
|
32850
32850
|
|
|
32851
|
-
// src/
|
|
32852
|
-
|
|
32853
|
-
|
|
32854
|
-
|
|
32855
|
-
}
|
|
32856
|
-
|
|
32857
|
-
|
|
32858
|
-
|
|
32859
|
-
|
|
32860
|
-
|
|
32861
|
-
|
|
32862
|
-
|
|
32863
|
-
|
|
32864
|
-
|
|
32865
|
-
|
|
32866
|
-
|
|
32867
|
-
|
|
32851
|
+
// src/sdk/governance.ts
|
|
32852
|
+
var DEFAULT_OUTPUT_GOVERNANCE = {
|
|
32853
|
+
defaultVisibility: "private",
|
|
32854
|
+
redactPatterns: [
|
|
32855
|
+
/\bsk-[A-Za-z0-9_-]{8,}\b/g,
|
|
32856
|
+
/\bsk_[A-Za-z0-9_-]{8,}\b/g,
|
|
32857
|
+
/\bgh[opsur]_[A-Za-z0-9_]{8,}\b/g,
|
|
32858
|
+
/\bgithub_pat_[A-Za-z0-9_]{8,}\b/g,
|
|
32859
|
+
/\bnpm_[A-Za-z0-9_]{8,}\b/g,
|
|
32860
|
+
/\bAKIA[A-Z0-9]{12,}\b/g,
|
|
32861
|
+
/\bAIza[A-Za-z0-9_-]{10,}\b/g,
|
|
32862
|
+
/\b[A-Z0-9_]*(?:API_KEY|SECRET|TOKEN|PASSWORD|DATABASE_URL)[A-Z0-9_]*\s*[:=]\s*[^ \n\r\t]+/gi,
|
|
32863
|
+
/\bhttps?:\/\/[^ \n\r\t]+X-Amz-Signature=[^ \n\r\t]+/gi
|
|
32864
|
+
],
|
|
32865
|
+
perOutputBytes: 10 * 1024 * 1024,
|
|
32866
|
+
perRunTotalBytes: 100 * 1024 * 1024,
|
|
32867
|
+
artifactTtlSeconds: 30 * 24 * 60 * 60
|
|
32868
|
+
};
|
|
32869
|
+
var DEFAULT_RUN_QUOTA = {
|
|
32870
|
+
cpu: 1,
|
|
32871
|
+
memoryMB: 2048,
|
|
32872
|
+
durationSeconds: 3600,
|
|
32873
|
+
networkMB: 100,
|
|
32874
|
+
artifactBytes: 100 * 1024 * 1024
|
|
32875
|
+
};
|
|
32876
|
+
|
|
32877
|
+
// src/server/database-url.ts
|
|
32878
|
+
import { isAbsolute, join as join3 } from "path";
|
|
32879
|
+
import { fileURLToPath } from "url";
|
|
32880
|
+
|
|
32881
|
+
// src/lib/config.ts
|
|
32882
|
+
import { existsSync, readFileSync as readFileSync2, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "fs";
|
|
32883
|
+
import { join as join2, dirname as dirname2 } from "path";
|
|
32884
|
+
import { homedir as homedir2 } from "os";
|
|
32868
32885
|
|
|
32869
32886
|
// src/lib/retired-settings.ts
|
|
32870
32887
|
var RETIRED_ENV_SUFFIXES = ["_STORAGE_MODE", "_DEPLOYMENT_MODE", "_CLOUD_MODE"];
|
|
@@ -32901,54 +32918,7 @@ function assertNoRetiredModeEnvVars(env, options) {
|
|
|
32901
32918
|
throw new RetiredSettingError(names[0], `${names.join(", ")} ${names.length === 1 ? "is" : "are"} no longer read. ` + "Deployment modes were removed: where a server keeps its data is decided by the " + `database it is given, not by a declared label. Set ${options.replacement} to a ` + "postgres:// URL to use PostgreSQL, or leave it unset for the on-box SQLite database. " + `Then unset ${names.join(" and ")}. ` + "Refused rather than ignored, because a discarded setting looks exactly like a " + "working one until something needs the data.");
|
|
32902
32919
|
}
|
|
32903
32920
|
|
|
32904
|
-
// src/server/config.ts
|
|
32905
|
-
var DATABASE_URL_ENV = "HASNA_SKILLS_DATABASE_URL";
|
|
32906
|
-
var SKILLS_ENV_NAMESPACE = "SKILLS";
|
|
32907
|
-
function resolveServerConfig(env = process.env) {
|
|
32908
|
-
assertNoRetiredModeEnvVars(env, {
|
|
32909
|
-
app: SKILLS_ENV_NAMESPACE,
|
|
32910
|
-
replacement: DATABASE_URL_ENV
|
|
32911
|
-
});
|
|
32912
|
-
const nodeEnv = env.NODE_ENV || "development";
|
|
32913
|
-
const host = env.HOST || env.SKILLS_HOST || "0.0.0.0";
|
|
32914
|
-
const port = parsePositiveInt(env.PORT || env.SKILLS_PORT, 8787);
|
|
32915
|
-
return {
|
|
32916
|
-
host,
|
|
32917
|
-
port,
|
|
32918
|
-
databaseUrl: env[DATABASE_URL_ENV] || env.DATABASE_URL || undefined,
|
|
32919
|
-
bootstrapApiKey: env.HASNA_SKILLS_BOOTSTRAP_API_KEY || undefined,
|
|
32920
|
-
artifactBucket: env.HASNA_SKILLS_S3_BUCKET || env.SKILLS_S3_BUCKET || undefined,
|
|
32921
|
-
artifactPrefix: normalizePrefix(env.HASNA_SKILLS_S3_PREFIX || env.SKILLS_S3_PREFIX || "skills/artifacts"),
|
|
32922
|
-
inlineWorker: env.HASNA_SKILLS_INLINE_WORKER === "1",
|
|
32923
|
-
bundleSigningKey: env.HASNA_SKILLS_API_SIGNING_KEY || env.HASNA_SKILLS_SIGNING_KEY || undefined,
|
|
32924
|
-
requestBodyLimitBytes: parsePositiveInt(env.HASNA_SKILLS_REQUEST_BODY_LIMIT_BYTES, 1e6),
|
|
32925
|
-
skillBundleLimitBytes: parsePositiveInt(env.HASNA_SKILLS_BUNDLE_LIMIT_BYTES, 25000000),
|
|
32926
|
-
tombstoneWindowMs: parsePositiveInt(env.HASNA_SKILLS_TOMBSTONE_WINDOW_MS, 7 * 24 * 60 * 60 * 1000),
|
|
32927
|
-
publicBaseUrl: (env.SKILLS_PUBLIC_BASE_URL || localOrigin(host, port)).replace(/\/+$/, ""),
|
|
32928
|
-
nodeEnv,
|
|
32929
|
-
allowEphemeralStore: env.HASNA_SKILLS_ALLOW_EPHEMERAL_STORE === "1"
|
|
32930
|
-
};
|
|
32931
|
-
}
|
|
32932
|
-
function localOrigin(host, port) {
|
|
32933
|
-
const hostname = host === "0.0.0.0" || host === "::" ? "localhost" : host;
|
|
32934
|
-
return `http://${hostname.includes(":") ? `[${hostname}]` : hostname}:${port}`;
|
|
32935
|
-
}
|
|
32936
|
-
function parsePositiveInt(value, fallback) {
|
|
32937
|
-
const parsed = Number.parseInt(value ?? "", 10);
|
|
32938
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
32939
|
-
}
|
|
32940
|
-
function normalizePrefix(value) {
|
|
32941
|
-
return value.replace(/^\/+|\/+$/g, "") || "skills/artifacts";
|
|
32942
|
-
}
|
|
32943
|
-
|
|
32944
|
-
// src/server/database-url.ts
|
|
32945
|
-
import { isAbsolute, join as join3 } from "path";
|
|
32946
|
-
import { fileURLToPath } from "url";
|
|
32947
|
-
|
|
32948
32921
|
// src/lib/config.ts
|
|
32949
|
-
import { existsSync, readFileSync as readFileSync2, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "fs";
|
|
32950
|
-
import { join as join2, dirname as dirname2 } from "path";
|
|
32951
|
-
import { homedir as homedir2 } from "os";
|
|
32952
32922
|
function mergeDirectoryContents(sourceDir, targetDir) {
|
|
32953
32923
|
if (!existsSync(sourceDir))
|
|
32954
32924
|
return;
|
|
@@ -33059,39 +33029,66 @@ function looksLikeSqlitePath(value) {
|
|
|
33059
33029
|
return SQLITE_EXTENSIONS.some((extension) => value.toLowerCase().endsWith(extension));
|
|
33060
33030
|
}
|
|
33061
33031
|
|
|
33062
|
-
// src/server/
|
|
33063
|
-
import {
|
|
33032
|
+
// src/server/sqlite-store.ts
|
|
33033
|
+
import { Database } from "bun:sqlite";
|
|
33034
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
33035
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
|
|
33036
|
+
import { dirname as dirname4, join as join5 } from "path";
|
|
33064
33037
|
|
|
33065
|
-
// src/server/
|
|
33066
|
-
import {
|
|
33038
|
+
// src/server/auth.ts
|
|
33039
|
+
import { createHash as createHash3 } from "crypto";
|
|
33040
|
+
function hashApiKey(token) {
|
|
33041
|
+
return createHash3("sha256").update(token).digest("hex");
|
|
33042
|
+
}
|
|
33043
|
+
function publicPrincipal(partial = {}) {
|
|
33044
|
+
return {
|
|
33045
|
+
apiKeyId: partial.apiKeyId || "key_dev",
|
|
33046
|
+
orgId: partial.orgId || "org_dev",
|
|
33047
|
+
orgSlug: partial.orgSlug || "dev",
|
|
33048
|
+
orgName: partial.orgName || "Development",
|
|
33049
|
+
userId: partial.userId || "user_dev",
|
|
33050
|
+
email: partial.email || "dev@example.com",
|
|
33051
|
+
role: partial.role || "owner",
|
|
33052
|
+
scopes: partial.scopes || ["skills:read", "runs:write"]
|
|
33053
|
+
};
|
|
33054
|
+
}
|
|
33067
33055
|
|
|
33068
|
-
// src/server/
|
|
33069
|
-
|
|
33070
|
-
|
|
33071
|
-
|
|
33072
|
-
|
|
33073
|
-
|
|
33074
|
-
|
|
33075
|
-
|
|
33076
|
-
|
|
33077
|
-
|
|
33078
|
-
|
|
33079
|
-
|
|
33080
|
-
|
|
33056
|
+
// src/server/migrations-dir.ts
|
|
33057
|
+
import { existsSync as existsSync2 } from "fs";
|
|
33058
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
33059
|
+
var MIGRATION_DIALECTS = ["postgres", "sqlite"];
|
|
33060
|
+
var MAX_WALK_UP = 6;
|
|
33061
|
+
function findMigrationsRoot(startDirs = defaultStartDirs()) {
|
|
33062
|
+
for (const start of startDirs) {
|
|
33063
|
+
let dir = start;
|
|
33064
|
+
for (let level = 0;level < MAX_WALK_UP; level += 1) {
|
|
33065
|
+
const candidate = join4(dir, "migrations");
|
|
33066
|
+
if (MIGRATION_DIALECTS.some((dialect) => existsSync2(join4(candidate, dialect))))
|
|
33067
|
+
return candidate;
|
|
33068
|
+
const parent = dirname3(dir);
|
|
33069
|
+
if (parent === dir)
|
|
33070
|
+
break;
|
|
33071
|
+
dir = parent;
|
|
33072
|
+
}
|
|
33081
33073
|
}
|
|
33074
|
+
return null;
|
|
33082
33075
|
}
|
|
33083
|
-
|
|
33084
|
-
|
|
33085
|
-
|
|
33086
|
-
expectedRevisionId;
|
|
33087
|
-
currentRevisionId;
|
|
33088
|
-
constructor(slug, expectedRevisionId, currentRevisionId) {
|
|
33089
|
-
super(`revision conflict for '${slug}': expected revision ${expectedRevisionId ?? "(none)"}, ` + `current is ${currentRevisionId ?? "(none)"}. Refused rather than silently overwriting a newer revision.`);
|
|
33090
|
-
this.name = "SkillRevisionConflictError";
|
|
33091
|
-
this.slug = slug;
|
|
33092
|
-
this.expectedRevisionId = expectedRevisionId;
|
|
33093
|
-
this.currentRevisionId = currentRevisionId;
|
|
33076
|
+
function resolveMigrationsDir(dialect, root3 = findMigrationsRoot()) {
|
|
33077
|
+
if (!root3) {
|
|
33078
|
+
throw new Error(`could not locate the migrations directory for dialect "${dialect}". ` + `Expected a migrations/${dialect}/ folder alongside the package root.`);
|
|
33094
33079
|
}
|
|
33080
|
+
const dir = join4(root3, dialect);
|
|
33081
|
+
if (!existsSync2(dir)) {
|
|
33082
|
+
throw new Error(`migrations directory not found: ${dir}`);
|
|
33083
|
+
}
|
|
33084
|
+
return dir;
|
|
33085
|
+
}
|
|
33086
|
+
function defaultStartDirs() {
|
|
33087
|
+
const dirs = [import.meta.dir];
|
|
33088
|
+
const cwd = process.cwd();
|
|
33089
|
+
if (cwd && cwd !== import.meta.dir)
|
|
33090
|
+
dirs.push(cwd);
|
|
33091
|
+
return dirs;
|
|
33095
33092
|
}
|
|
33096
33093
|
|
|
33097
33094
|
// src/server/rows.ts
|
|
@@ -33239,6 +33236,35 @@ function dateString(value) {
|
|
|
33239
33236
|
return String(value);
|
|
33240
33237
|
}
|
|
33241
33238
|
|
|
33239
|
+
// src/server/types.ts
|
|
33240
|
+
class StaleLeaseGenerationError extends Error {
|
|
33241
|
+
runId;
|
|
33242
|
+
expectedGeneration;
|
|
33243
|
+
currentGeneration;
|
|
33244
|
+
status;
|
|
33245
|
+
constructor(runId2, expectedGeneration, currentGeneration, status) {
|
|
33246
|
+
super(`late transition rejected for run ${runId2}: expected lease_generation ${expectedGeneration}, ` + `current ${currentGeneration} (status ${status})`);
|
|
33247
|
+
this.name = "StaleLeaseGenerationError";
|
|
33248
|
+
this.runId = runId2;
|
|
33249
|
+
this.expectedGeneration = expectedGeneration;
|
|
33250
|
+
this.currentGeneration = currentGeneration;
|
|
33251
|
+
this.status = status;
|
|
33252
|
+
}
|
|
33253
|
+
}
|
|
33254
|
+
|
|
33255
|
+
class SkillRevisionConflictError extends Error {
|
|
33256
|
+
slug;
|
|
33257
|
+
expectedRevisionId;
|
|
33258
|
+
currentRevisionId;
|
|
33259
|
+
constructor(slug, expectedRevisionId, currentRevisionId) {
|
|
33260
|
+
super(`revision conflict for '${slug}': expected revision ${expectedRevisionId ?? "(none)"}, ` + `current is ${currentRevisionId ?? "(none)"}. Refused rather than silently overwriting a newer revision.`);
|
|
33261
|
+
this.name = "SkillRevisionConflictError";
|
|
33262
|
+
this.slug = slug;
|
|
33263
|
+
this.expectedRevisionId = expectedRevisionId;
|
|
33264
|
+
this.currentRevisionId = currentRevisionId;
|
|
33265
|
+
}
|
|
33266
|
+
}
|
|
33267
|
+
|
|
33242
33268
|
// src/lib/revision.ts
|
|
33243
33269
|
import { createHash as createHash4 } from "crypto";
|
|
33244
33270
|
function revisionIdOf(content) {
|
|
@@ -33261,50 +33287,6 @@ function revisionIdOfRecord(record) {
|
|
|
33261
33287
|
return revisionIdOf(record);
|
|
33262
33288
|
}
|
|
33263
33289
|
|
|
33264
|
-
// src/server/sqlite-store.ts
|
|
33265
|
-
import { Database } from "bun:sqlite";
|
|
33266
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
33267
|
-
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
|
|
33268
|
-
import { dirname as dirname4, join as join5 } from "path";
|
|
33269
|
-
|
|
33270
|
-
// src/server/migrations-dir.ts
|
|
33271
|
-
import { existsSync as existsSync2 } from "fs";
|
|
33272
|
-
import { dirname as dirname3, join as join4 } from "path";
|
|
33273
|
-
var MIGRATION_DIALECTS = ["postgres", "sqlite"];
|
|
33274
|
-
var MAX_WALK_UP = 6;
|
|
33275
|
-
function findMigrationsRoot(startDirs = defaultStartDirs()) {
|
|
33276
|
-
for (const start of startDirs) {
|
|
33277
|
-
let dir = start;
|
|
33278
|
-
for (let level = 0;level < MAX_WALK_UP; level += 1) {
|
|
33279
|
-
const candidate = join4(dir, "migrations");
|
|
33280
|
-
if (MIGRATION_DIALECTS.some((dialect) => existsSync2(join4(candidate, dialect))))
|
|
33281
|
-
return candidate;
|
|
33282
|
-
const parent = dirname3(dir);
|
|
33283
|
-
if (parent === dir)
|
|
33284
|
-
break;
|
|
33285
|
-
dir = parent;
|
|
33286
|
-
}
|
|
33287
|
-
}
|
|
33288
|
-
return null;
|
|
33289
|
-
}
|
|
33290
|
-
function resolveMigrationsDir(dialect, root3 = findMigrationsRoot()) {
|
|
33291
|
-
if (!root3) {
|
|
33292
|
-
throw new Error(`could not locate the migrations directory for dialect "${dialect}". ` + `Expected a migrations/${dialect}/ folder alongside the package root.`);
|
|
33293
|
-
}
|
|
33294
|
-
const dir = join4(root3, dialect);
|
|
33295
|
-
if (!existsSync2(dir)) {
|
|
33296
|
-
throw new Error(`migrations directory not found: ${dir}`);
|
|
33297
|
-
}
|
|
33298
|
-
return dir;
|
|
33299
|
-
}
|
|
33300
|
-
function defaultStartDirs() {
|
|
33301
|
-
const dirs = [import.meta.dir];
|
|
33302
|
-
const cwd = process.cwd();
|
|
33303
|
-
if (cwd && cwd !== import.meta.dir)
|
|
33304
|
-
dirs.push(cwd);
|
|
33305
|
-
return dirs;
|
|
33306
|
-
}
|
|
33307
|
-
|
|
33308
33290
|
// src/server/sqlite-store.ts
|
|
33309
33291
|
var CLAIM_ATTEMPTS = 8;
|
|
33310
33292
|
var CLAIMABLE_STATUSES = ["queued", "retrying"];
|
|
@@ -33895,7 +33877,51 @@ function parseScopes(value) {
|
|
|
33895
33877
|
}
|
|
33896
33878
|
}
|
|
33897
33879
|
|
|
33880
|
+
// src/server/config.ts
|
|
33881
|
+
var DATABASE_URL_ENV = "HASNA_SKILLS_DATABASE_URL";
|
|
33882
|
+
var SKILLS_ENV_NAMESPACE = "SKILLS";
|
|
33883
|
+
function resolveServerConfig(env = process.env) {
|
|
33884
|
+
assertNoRetiredModeEnvVars(env, {
|
|
33885
|
+
app: SKILLS_ENV_NAMESPACE,
|
|
33886
|
+
replacement: DATABASE_URL_ENV
|
|
33887
|
+
});
|
|
33888
|
+
const nodeEnv = env.NODE_ENV || "development";
|
|
33889
|
+
const host = env.HOST || env.SKILLS_HOST || "0.0.0.0";
|
|
33890
|
+
const port = parsePositiveInt(env.PORT || env.SKILLS_PORT, 8787);
|
|
33891
|
+
return {
|
|
33892
|
+
host,
|
|
33893
|
+
port,
|
|
33894
|
+
databaseUrl: env[DATABASE_URL_ENV] || env.DATABASE_URL || undefined,
|
|
33895
|
+
bootstrapApiKey: env.HASNA_SKILLS_BOOTSTRAP_API_KEY || undefined,
|
|
33896
|
+
artifactBucket: env.HASNA_SKILLS_S3_BUCKET || env.SKILLS_S3_BUCKET || undefined,
|
|
33897
|
+
artifactPrefix: normalizePrefix(env.HASNA_SKILLS_S3_PREFIX || env.SKILLS_S3_PREFIX || "skills/artifacts"),
|
|
33898
|
+
inlineWorker: env.HASNA_SKILLS_INLINE_WORKER === "1",
|
|
33899
|
+
bundleSigningKey: env.HASNA_SKILLS_API_SIGNING_KEY || env.HASNA_SKILLS_SIGNING_KEY || undefined,
|
|
33900
|
+
requestBodyLimitBytes: parsePositiveInt(env.HASNA_SKILLS_REQUEST_BODY_LIMIT_BYTES, 1e6),
|
|
33901
|
+
skillBundleLimitBytes: parsePositiveInt(env.HASNA_SKILLS_BUNDLE_LIMIT_BYTES, 25000000),
|
|
33902
|
+
tombstoneWindowMs: parsePositiveInt(env.HASNA_SKILLS_TOMBSTONE_WINDOW_MS, 7 * 24 * 60 * 60 * 1000),
|
|
33903
|
+
publicBaseUrl: (env.SKILLS_PUBLIC_BASE_URL || localOrigin(host, port)).replace(/\/+$/, ""),
|
|
33904
|
+
nodeEnv,
|
|
33905
|
+
allowEphemeralStore: env.HASNA_SKILLS_ALLOW_EPHEMERAL_STORE === "1"
|
|
33906
|
+
};
|
|
33907
|
+
}
|
|
33908
|
+
function localOrigin(host, port) {
|
|
33909
|
+
const hostname = host === "0.0.0.0" || host === "::" ? "localhost" : host;
|
|
33910
|
+
return `http://${hostname.includes(":") ? `[${hostname}]` : hostname}:${port}`;
|
|
33911
|
+
}
|
|
33912
|
+
function parsePositiveInt(value, fallback) {
|
|
33913
|
+
const parsed = Number.parseInt(value ?? "", 10);
|
|
33914
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
33915
|
+
}
|
|
33916
|
+
function normalizePrefix(value) {
|
|
33917
|
+
return value.replace(/^\/+|\/+$/g, "") || "skills/artifacts";
|
|
33918
|
+
}
|
|
33919
|
+
|
|
33920
|
+
// src/server/handlers.ts
|
|
33921
|
+
import { createHash as createHash5 } from "crypto";
|
|
33922
|
+
|
|
33898
33923
|
// src/server/store.ts
|
|
33924
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
33899
33925
|
function recordFieldsOf(input, carriedBundle, carriedSkillMd) {
|
|
33900
33926
|
return {
|
|
33901
33927
|
slug: input.slug,
|
|
@@ -34298,17 +34324,17 @@ class PostgresSkillsStore {
|
|
|
34298
34324
|
});
|
|
34299
34325
|
}
|
|
34300
34326
|
async createRun(input) {
|
|
34301
|
-
if (input.idempotencyKey) {
|
|
34302
|
-
const existing = await this.sql`
|
|
34303
|
-
SELECT * FROM skills_runs
|
|
34304
|
-
WHERE org_id = ${input.principal.orgId} AND idempotency_key = ${input.idempotencyKey}
|
|
34305
|
-
LIMIT 1
|
|
34306
|
-
`;
|
|
34307
|
-
if (existing[0])
|
|
34308
|
-
return rowToRun(existing[0]);
|
|
34309
|
-
}
|
|
34310
|
-
const id = runId();
|
|
34311
34327
|
return this.withContext(input.principal.orgId, false, async (tx) => {
|
|
34328
|
+
if (input.idempotencyKey) {
|
|
34329
|
+
const existing = await tx`
|
|
34330
|
+
SELECT * FROM skills_runs
|
|
34331
|
+
WHERE org_id = ${input.principal.orgId} AND idempotency_key = ${input.idempotencyKey}
|
|
34332
|
+
LIMIT 1
|
|
34333
|
+
`;
|
|
34334
|
+
if (existing[0])
|
|
34335
|
+
return rowToRun(existing[0]);
|
|
34336
|
+
}
|
|
34337
|
+
const id = runId();
|
|
34312
34338
|
const rows = await tx`
|
|
34313
34339
|
INSERT INTO skills_runs (id, org_id, user_id, skill_slug, requested_slug, status, input_json, args_json, idempotency_key, correlation_id)
|
|
34314
34340
|
VALUES (${id}, ${input.principal.orgId}, ${input.principal.userId}, ${input.slug}, ${input.slug}, ${"queued"}, ${JSON.stringify(input.input)}::jsonb, ${JSON.stringify(input.args)}::jsonb, ${input.idempotencyKey ?? null}, ${randomUUID3()})
|
|
@@ -34850,7 +34876,9 @@ async function completeRun(store, run, preview) {
|
|
|
34850
34876
|
return next ?? run;
|
|
34851
34877
|
}
|
|
34852
34878
|
async function failRun(store, run, code, message) {
|
|
34853
|
-
|
|
34879
|
+
try {
|
|
34880
|
+
await store.appendLog(run.id, run.orgId, "error", message);
|
|
34881
|
+
} catch {}
|
|
34854
34882
|
const next = await fencedTransition(store, run, {
|
|
34855
34883
|
status: "failed",
|
|
34856
34884
|
errorCode: code,
|
|
@@ -34864,7 +34892,9 @@ async function fencedTransition(store, run, patch) {
|
|
|
34864
34892
|
return store.updateRun(run.id, patch);
|
|
34865
34893
|
const next = await store.transitionRun(run.id, patch, run.leaseGeneration);
|
|
34866
34894
|
if (!next) {
|
|
34867
|
-
|
|
34895
|
+
try {
|
|
34896
|
+
await store.appendLog(run.id, run.orgId, "warn", `late write rejected: run no longer owned at lease_generation ${run.leaseGeneration}`);
|
|
34897
|
+
} catch {}
|
|
34868
34898
|
}
|
|
34869
34899
|
return next;
|
|
34870
34900
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,6 @@ export { SKILLS_CLI_MCP_PARITY, findSkillsParityForCliCommand, findSkillsParityF
|
|
|
31
31
|
export { createRegistrySyncArtifact, writeRegistrySyncArtifact, type RegistrySyncArtifact, type RegistrySyncOptions, type RegistrySyncSkill, } from "./lib/registry-sync.js";
|
|
32
32
|
export { MCP_CONTRACT_SCHEMA_VERSION, createMcpContractManifest, createSkillMcpMetadata, describeMcpToolContracts, getMcpResourceContracts, getMcpToolDescriptions, listMcpToolContracts, summarizeMcpToolContract, type DescribedMcpToolContract, type JsonSchemaObject, type McpContractManifest, type McpResourceContract, type McpToolCategory, type McpToolContract, type McpToolSideEffect, type SkillMcpMetadata, type SkillMcpSchemaContract, type UnknownMcpToolContract, } from "./lib/mcp-contracts.js";
|
|
33
33
|
export { getFeedbackDbPath, saveFeedback, type FeedbackCategory, type FeedbackInput, type FeedbackResult, } from "./lib/feedback.js";
|
|
34
|
-
export { SKILLS_NATIVE_STORAGE_ENV, SKILLS_NATIVE_STORAGE_FALLBACK_ENV, SKILLS_STORAGE_ENV, SKILLS_STORAGE_FALLBACK_ENV, SKILLS_STORAGE_TABLES, STORAGE_TABLES, SkillsPostgresSyncStore, SkillsS3ObjectStore, buildSkillsS3ObjectUrl, createSkillsPostgresSyncStore, createSkillsS3ObjectStore, createSkillsSnapshotSyncRecord, exportSkillsLocalSnapshot, getSkillsNativeStorageStatus, getSkillsStorageDatabaseEnv, getSkillsStorageDatabaseUrl, getSkillsStorageStatus, getStorageDatabaseEnv, getStorageDatabaseUrl, getStorageStatus, importSkillsLocalSnapshot, planSkillsS3SnapshotUpload, resolveSkillsNativeStorageConfig, resolveStorageConfig, signSkillsAwsV4Request, skillsPostgresSyncSchemaSql, uploadSkillsSnapshotFilesToS3, type AwsCredentials, type SignSkillsAwsV4RequestOptions, type SkillsFetch, type SkillsLocalSnapshot, type SkillsNativeStorageConfig, type SkillsNativeStorageStatus, type SkillsPostgresQueryClient, type SkillsS3ObjectStoreOptions, type SkillsS3PutObjectOptions, type SkillsS3SnapshotPlanEntry, type SkillsS3StoredObject, type SkillsSnapshotFile, type SkillsStorageTable, type SkillsSyncRecord, } from "./lib/native-storage.js";
|
|
34
|
+
export { SKILLS_NATIVE_STORAGE_ENV, SKILLS_NATIVE_STORAGE_FALLBACK_ENV, SKILLS_STORAGE_ENV, SKILLS_STORAGE_FALLBACK_ENV, SKILLS_STORAGE_TABLES, STORAGE_TABLES, SkillsPostgresSyncStore, SkillsS3ObjectStore, buildSkillsS3ObjectUrl, createSkillsPostgresSyncStore, createSkillsS3ObjectStore, createSkillsSnapshotSyncRecord, exportSkillsLocalSnapshot, getSkillsNativeStorageStatus, getSkillsStorageDatabaseEnv, getSkillsStorageDatabaseUrl, getSkillsStorageStatus, getStorageDatabaseEnv, getStorageDatabaseUrl, getStorageStatus, importSkillsLocalSnapshot, planSkillsS3SnapshotUpload, resolveSkillsNativeStorageConfig, resolveStorageConfig, signSkillsAwsV4Request, skillsPostgresSyncSchemaSql, storageCapabilities, uploadSkillsSnapshotFilesToS3, type AwsCredentials, type SignSkillsAwsV4RequestOptions, type SkillsFetch, type SkillsLocalSnapshot, type SkillsNativeStorageConfig, type SkillsNativeStorageStatus, type SkillsPostgresQueryClient, type SkillsS3ObjectStoreOptions, type SkillsS3PutObjectOptions, type SkillsS3SnapshotPlanEntry, type SkillsS3StoredObject, type SkillsSnapshotFile, type SkillsStorageTable, type SkillsSyncRecord, } from "./lib/native-storage.js";
|
|
35
35
|
export { SKILL_ALIASES, normalizeSkillSlug, resolveSkillAlias, type SkillAlias, } from "./lib/skill-aliases.js";
|
|
36
36
|
export type { SkillResponse, SkillDetailResponse, CategoryResponse, TagResponse, InstallResponse, RemoveResponse, VersionResponse, ExportResponse, ImportResponse, SearchResponse, CategoryInstallResponse, ErrorResponse, } from "./types/api.js";
|