@hasna/skills 0.1.44 → 0.1.46
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 +36 -0
- package/bin/index.js +52538 -10651
- package/bin/mcp.js +346 -4
- package/dist/cli/commands/storage.d.ts +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +661 -4
- package/dist/lib/mcp-contracts.d.ts +1 -1
- package/dist/lib/native-storage.d.ts +251 -0
- package/dist/mcp/storage-tools.d.ts +2 -0
- package/dist/storage.d.ts +1 -0
- package/dist/storage.js +854 -0
- package/package.json +8 -2
package/dist/index.js
CHANGED
|
@@ -1320,12 +1320,47 @@ function ensurePortableSkillFiles(skillPath, manifest) {
|
|
|
1320
1320
|
writeFileSync2(join3(skillPath, "skill.json"), renderSkillJson(next));
|
|
1321
1321
|
if (!existsSync3(join3(skillPath, "AGENTS.md")))
|
|
1322
1322
|
writeFileSync2(join3(skillPath, "AGENTS.md"), renderAgentsMd(next));
|
|
1323
|
-
|
|
1324
|
-
writeFileSync2(join3(skillPath, "package.json"), renderPackageJson(next));
|
|
1323
|
+
ensurePackageJson(skillPath, next);
|
|
1325
1324
|
if (!existsSync3(join3(skillPath, "tsconfig.json")))
|
|
1326
1325
|
writeFileSync2(join3(skillPath, "tsconfig.json"), renderTsconfig());
|
|
1327
1326
|
return readPortableSkillManifest(skillPath, next.name);
|
|
1328
1327
|
}
|
|
1328
|
+
function ensurePackageJson(skillPath, manifest) {
|
|
1329
|
+
const pkgPath = join3(skillPath, "package.json");
|
|
1330
|
+
const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
|
|
1331
|
+
const commandName = normalizePortableSkillName(first.name || manifest.name);
|
|
1332
|
+
const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
|
|
1333
|
+
if (!existsSync3(pkgPath)) {
|
|
1334
|
+
writeFileSync2(pkgPath, renderPackageJson(manifest));
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
const existing = readJsonObject(pkgPath);
|
|
1338
|
+
const bin = {};
|
|
1339
|
+
if (isRecord(existing.bin)) {
|
|
1340
|
+
for (const [name, value] of Object.entries(existing.bin)) {
|
|
1341
|
+
if (typeof value === "string" && value.trim())
|
|
1342
|
+
bin[normalizePortableSkillName(name)] = value.replace(/^\.\//, "");
|
|
1343
|
+
}
|
|
1344
|
+
} else {
|
|
1345
|
+
const binEntry = stringValue(existing.bin);
|
|
1346
|
+
if (binEntry)
|
|
1347
|
+
bin[manifest.name] = binEntry.replace(/^\.\//, "");
|
|
1348
|
+
}
|
|
1349
|
+
bin[commandName] = entry;
|
|
1350
|
+
const scripts = isRecord(existing.scripts) ? { ...existing.scripts } : {};
|
|
1351
|
+
if (!stringValue(scripts.dev))
|
|
1352
|
+
scripts.dev = `bun run ${entry}`;
|
|
1353
|
+
writeFileSync2(pkgPath, `${JSON.stringify({
|
|
1354
|
+
...existing,
|
|
1355
|
+
name: manifest.name,
|
|
1356
|
+
version: manifest.version,
|
|
1357
|
+
description: manifest.description,
|
|
1358
|
+
type: stringValue(existing.type) ?? "module",
|
|
1359
|
+
bin,
|
|
1360
|
+
scripts
|
|
1361
|
+
}, null, 2)}
|
|
1362
|
+
`);
|
|
1363
|
+
}
|
|
1329
1364
|
function copySkillDirectory(source, destination) {
|
|
1330
1365
|
mkdirSync2(destination, { recursive: true });
|
|
1331
1366
|
cpSync(source, destination, {
|
|
@@ -18776,7 +18811,7 @@ import { dirname as dirname4, relative as relative3 } from "path";
|
|
|
18776
18811
|
// package.json
|
|
18777
18812
|
var package_default = {
|
|
18778
18813
|
name: "@hasna/skills",
|
|
18779
|
-
version: "0.1.
|
|
18814
|
+
version: "0.1.46",
|
|
18780
18815
|
description: "Skills library for AI coding agents",
|
|
18781
18816
|
type: "module",
|
|
18782
18817
|
bin: {
|
|
@@ -18787,6 +18822,10 @@ var package_default = {
|
|
|
18787
18822
|
".": {
|
|
18788
18823
|
import: "./dist/index.js",
|
|
18789
18824
|
types: "./dist/index.d.ts"
|
|
18825
|
+
},
|
|
18826
|
+
"./storage": {
|
|
18827
|
+
import: "./dist/storage.js",
|
|
18828
|
+
types: "./dist/storage.d.ts"
|
|
18790
18829
|
}
|
|
18791
18830
|
},
|
|
18792
18831
|
files: [
|
|
@@ -18807,7 +18846,7 @@ var package_default = {
|
|
|
18807
18846
|
types: "./dist/index.d.ts",
|
|
18808
18847
|
scripts: {
|
|
18809
18848
|
clean: "rm -rf bin/ dist/",
|
|
18810
|
-
build: "bun run clean && bun build ./src/cli/index.tsx --outdir ./bin --target bun
|
|
18849
|
+
build: "bun run clean && bun build ./src/cli/index.tsx --outdir ./bin --target bun && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/index.ts ./src/storage.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
18811
18850
|
test: "bun test",
|
|
18812
18851
|
dev: "bun run ./src/cli/index.tsx",
|
|
18813
18852
|
"dev:watch": "bun --watch run ./src/cli/index.tsx",
|
|
@@ -18837,9 +18876,11 @@ var package_default = {
|
|
|
18837
18876
|
devDependencies: {
|
|
18838
18877
|
"@types/bun": "latest",
|
|
18839
18878
|
"@types/react": "^18.2.0",
|
|
18879
|
+
"react-devtools-core": "^7.0.1",
|
|
18840
18880
|
typescript: "^5"
|
|
18841
18881
|
},
|
|
18842
18882
|
dependencies: {
|
|
18883
|
+
"@hasna/events": "^0.1.3",
|
|
18843
18884
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
18844
18885
|
chalk: "^5.3.0",
|
|
18845
18886
|
commander: "^12.1.0",
|
|
@@ -19314,6 +19355,46 @@ var toolContracts = [
|
|
|
19314
19355
|
inputSchema: objectSchema(),
|
|
19315
19356
|
outputSchema: objectSchema({}, [], "Setup summary.", true)
|
|
19316
19357
|
},
|
|
19358
|
+
{
|
|
19359
|
+
name: "storage_status",
|
|
19360
|
+
title: "Storage Status",
|
|
19361
|
+
description: "Show local-first storage paths and optional repo-owned Postgres/S3 readiness.",
|
|
19362
|
+
params: ["directory?"],
|
|
19363
|
+
category: "storage",
|
|
19364
|
+
sideEffects: "none",
|
|
19365
|
+
stable: true,
|
|
19366
|
+
inputSchema: objectSchema({ directory: stringSchema("Project directory.") }),
|
|
19367
|
+
outputSchema: objectSchema({
|
|
19368
|
+
package: stringSchema("Package name."),
|
|
19369
|
+
mode: { type: "string", enum: ["local", "remote", "hybrid"] },
|
|
19370
|
+
local: objectSchema({}, [], "Local storage paths.", true),
|
|
19371
|
+
remote: objectSchema({}, [], "Remote storage readiness.", true)
|
|
19372
|
+
}, ["package", "mode", "local", "remote"])
|
|
19373
|
+
},
|
|
19374
|
+
{
|
|
19375
|
+
name: "storage_sync_plan",
|
|
19376
|
+
title: "Storage Sync Plan",
|
|
19377
|
+
description: "Plan .skills snapshot sync for optional Postgres/S3 storage without network access.",
|
|
19378
|
+
params: ["directory?", "includeSchemaSql?"],
|
|
19379
|
+
category: "storage",
|
|
19380
|
+
sideEffects: "none",
|
|
19381
|
+
stable: true,
|
|
19382
|
+
inputSchema: objectSchema({
|
|
19383
|
+
directory: stringSchema("Project directory."),
|
|
19384
|
+
includeSchemaSql: { type: "boolean", default: false }
|
|
19385
|
+
}),
|
|
19386
|
+
outputSchema: objectSchema({
|
|
19387
|
+
package: stringSchema("Package name."),
|
|
19388
|
+
noNetwork: { type: "boolean", const: true },
|
|
19389
|
+
mode: { type: "string", enum: ["local", "remote", "hybrid"] },
|
|
19390
|
+
databaseConfigured: { type: "boolean" },
|
|
19391
|
+
s3Configured: { type: "boolean" },
|
|
19392
|
+
snapshotFileCount: { type: "number" },
|
|
19393
|
+
s3ObjectCount: { type: "number" },
|
|
19394
|
+
env: objectSchema({}, [], "Storage env var names.", true),
|
|
19395
|
+
schemaSql: stringSchema("Optional Postgres schema SQL.")
|
|
19396
|
+
}, ["package", "noNetwork", "mode", "databaseConfigured", "s3Configured"])
|
|
19397
|
+
},
|
|
19317
19398
|
{
|
|
19318
19399
|
name: "schedule_skill",
|
|
19319
19400
|
title: "Schedule Skill",
|
|
@@ -19666,6 +19747,553 @@ function saveFeedback(input) {
|
|
|
19666
19747
|
}
|
|
19667
19748
|
return { saved: true, category, path: getFeedbackDbPath() };
|
|
19668
19749
|
}
|
|
19750
|
+
// src/lib/native-storage.ts
|
|
19751
|
+
import { createHash as createHash2, createHmac } from "crypto";
|
|
19752
|
+
import {
|
|
19753
|
+
existsSync as existsSync12,
|
|
19754
|
+
mkdirSync as mkdirSync9,
|
|
19755
|
+
readFileSync as readFileSync11,
|
|
19756
|
+
readdirSync as readdirSync5,
|
|
19757
|
+
statSync as statSync4,
|
|
19758
|
+
writeFileSync as writeFileSync8
|
|
19759
|
+
} from "fs";
|
|
19760
|
+
import { dirname as dirname6, join as join12, normalize as normalize3, relative as relative4, sep } from "path";
|
|
19761
|
+
var SKILLS_STORAGE_TABLES = [
|
|
19762
|
+
"skills_sync_records",
|
|
19763
|
+
"skills_sync_cursors"
|
|
19764
|
+
];
|
|
19765
|
+
var STORAGE_TABLES = SKILLS_STORAGE_TABLES;
|
|
19766
|
+
var SKILLS_NATIVE_STORAGE_ENV = {
|
|
19767
|
+
mode: "HASNA_SKILLS_STORAGE_MODE",
|
|
19768
|
+
databaseUrl: "HASNA_SKILLS_DATABASE_URL",
|
|
19769
|
+
databaseSsl: "HASNA_SKILLS_DATABASE_SSL",
|
|
19770
|
+
databaseSchema: "HASNA_SKILLS_DATABASE_SCHEMA",
|
|
19771
|
+
s3Bucket: "HASNA_SKILLS_S3_BUCKET",
|
|
19772
|
+
s3Prefix: "HASNA_SKILLS_S3_PREFIX",
|
|
19773
|
+
awsRegion: "HASNA_SKILLS_AWS_REGION",
|
|
19774
|
+
s3Endpoint: "HASNA_SKILLS_S3_ENDPOINT",
|
|
19775
|
+
s3ForcePathStyle: "HASNA_SKILLS_S3_FORCE_PATH_STYLE",
|
|
19776
|
+
s3AccessKeyId: "HASNA_SKILLS_S3_ACCESS_KEY_ID",
|
|
19777
|
+
s3SecretAccessKey: "HASNA_SKILLS_S3_SECRET_ACCESS_KEY",
|
|
19778
|
+
s3SessionToken: "HASNA_SKILLS_S3_SESSION_TOKEN",
|
|
19779
|
+
syncBatchSize: "HASNA_SKILLS_SYNC_BATCH_SIZE",
|
|
19780
|
+
dryRun: "HASNA_SKILLS_SYNC_DRY_RUN"
|
|
19781
|
+
};
|
|
19782
|
+
var SKILLS_NATIVE_STORAGE_FALLBACK_ENV = {
|
|
19783
|
+
mode: "SKILLS_STORAGE_MODE",
|
|
19784
|
+
databaseUrl: "SKILLS_DATABASE_URL",
|
|
19785
|
+
databaseSsl: "SKILLS_DATABASE_SSL",
|
|
19786
|
+
databaseSchema: "SKILLS_DATABASE_SCHEMA",
|
|
19787
|
+
s3Bucket: "SKILLS_S3_BUCKET",
|
|
19788
|
+
s3Prefix: "SKILLS_S3_PREFIX",
|
|
19789
|
+
awsRegion: "SKILLS_AWS_REGION",
|
|
19790
|
+
s3Endpoint: "SKILLS_S3_ENDPOINT",
|
|
19791
|
+
s3ForcePathStyle: "SKILLS_S3_FORCE_PATH_STYLE",
|
|
19792
|
+
s3AccessKeyId: "SKILLS_S3_ACCESS_KEY_ID",
|
|
19793
|
+
s3SecretAccessKey: "SKILLS_S3_SECRET_ACCESS_KEY",
|
|
19794
|
+
s3SessionToken: "SKILLS_S3_SESSION_TOKEN",
|
|
19795
|
+
syncBatchSize: "SKILLS_SYNC_BATCH_SIZE",
|
|
19796
|
+
dryRun: "SKILLS_SYNC_DRY_RUN"
|
|
19797
|
+
};
|
|
19798
|
+
var SKILLS_STORAGE_ENV = SKILLS_NATIVE_STORAGE_ENV;
|
|
19799
|
+
var SKILLS_STORAGE_FALLBACK_ENV = SKILLS_NATIVE_STORAGE_FALLBACK_ENV;
|
|
19800
|
+
function resolveSkillsNativeStorageConfig(env = process.env) {
|
|
19801
|
+
const mode = getSkillsStorageMode(env);
|
|
19802
|
+
return {
|
|
19803
|
+
mode,
|
|
19804
|
+
databaseUrl: getSkillsStorageDatabaseUrl(env),
|
|
19805
|
+
databaseSsl: parseBoolean(readStorageEnv(env, "databaseSsl").value),
|
|
19806
|
+
databaseSchema: readStorageEnv(env, "databaseSchema").value,
|
|
19807
|
+
s3Bucket: readStorageEnv(env, "s3Bucket").value,
|
|
19808
|
+
s3Prefix: readStorageEnv(env, "s3Prefix").value,
|
|
19809
|
+
awsRegion: readStorageEnv(env, "awsRegion").value ?? "us-east-1",
|
|
19810
|
+
s3Endpoint: readStorageEnv(env, "s3Endpoint").value,
|
|
19811
|
+
s3ForcePathStyle: parseBoolean(readStorageEnv(env, "s3ForcePathStyle").value) ?? false,
|
|
19812
|
+
syncBatchSize: parsePositiveInteger(readStorageEnv(env, "syncBatchSize").value) ?? 500,
|
|
19813
|
+
dryRun: parseBoolean(readStorageEnv(env, "dryRun").value) ?? true
|
|
19814
|
+
};
|
|
19815
|
+
}
|
|
19816
|
+
function resolveStorageConfig(env = process.env) {
|
|
19817
|
+
return resolveSkillsNativeStorageConfig(env);
|
|
19818
|
+
}
|
|
19819
|
+
function getSkillsStorageMode(env = process.env) {
|
|
19820
|
+
return parseMode(readStorageEnv(env, "mode").value);
|
|
19821
|
+
}
|
|
19822
|
+
function getStorageMode(env = process.env) {
|
|
19823
|
+
return getSkillsStorageMode(env);
|
|
19824
|
+
}
|
|
19825
|
+
function getSkillsStorageDatabaseEnv(env = process.env) {
|
|
19826
|
+
return readStorageEnv(env, "databaseUrl").name;
|
|
19827
|
+
}
|
|
19828
|
+
function getStorageDatabaseEnv(env = process.env) {
|
|
19829
|
+
return getSkillsStorageDatabaseEnv(env);
|
|
19830
|
+
}
|
|
19831
|
+
function getSkillsStorageDatabaseUrl(env = process.env) {
|
|
19832
|
+
return readStorageEnv(env, "databaseUrl").value;
|
|
19833
|
+
}
|
|
19834
|
+
function getStorageDatabaseUrl(env = process.env) {
|
|
19835
|
+
return getSkillsStorageDatabaseUrl(env);
|
|
19836
|
+
}
|
|
19837
|
+
function getSkillsNativeStorageStatus(options = {}) {
|
|
19838
|
+
const env = options.env ?? process.env;
|
|
19839
|
+
const config2 = resolveSkillsNativeStorageConfig(env);
|
|
19840
|
+
const modeEnv = readStorageEnv(env, "mode");
|
|
19841
|
+
const databaseEnv = readStorageEnv(env, "databaseUrl");
|
|
19842
|
+
const s3BucketEnv = readStorageEnv(env, "s3Bucket");
|
|
19843
|
+
const targetDir = options.targetDir ?? process.cwd();
|
|
19844
|
+
return {
|
|
19845
|
+
package: "open-skills",
|
|
19846
|
+
mode: config2.mode,
|
|
19847
|
+
tables: [...SKILLS_STORAGE_TABLES],
|
|
19848
|
+
env: {
|
|
19849
|
+
mode: SKILLS_NATIVE_STORAGE_ENV.mode,
|
|
19850
|
+
databaseUrl: SKILLS_NATIVE_STORAGE_ENV.databaseUrl,
|
|
19851
|
+
s3Bucket: SKILLS_NATIVE_STORAGE_ENV.s3Bucket
|
|
19852
|
+
},
|
|
19853
|
+
local: {
|
|
19854
|
+
dataDir: getDataDir(),
|
|
19855
|
+
projectStateDir: getProjectStateDir(targetDir),
|
|
19856
|
+
feedbackDbPath: join12(getDataDir(), "skills.db")
|
|
19857
|
+
},
|
|
19858
|
+
remote: {
|
|
19859
|
+
databaseConfigured: Boolean(config2.databaseUrl),
|
|
19860
|
+
s3Configured: Boolean(config2.s3Bucket),
|
|
19861
|
+
databaseEnv: SKILLS_NATIVE_STORAGE_ENV.databaseUrl,
|
|
19862
|
+
s3BucketEnv: SKILLS_NATIVE_STORAGE_ENV.s3Bucket,
|
|
19863
|
+
activeModeEnv: modeEnv.name,
|
|
19864
|
+
activeDatabaseEnv: databaseEnv.name,
|
|
19865
|
+
activeS3BucketEnv: s3BucketEnv.name,
|
|
19866
|
+
region: config2.awsRegion ?? "us-east-1",
|
|
19867
|
+
dryRun: config2.dryRun
|
|
19868
|
+
}
|
|
19869
|
+
};
|
|
19870
|
+
}
|
|
19871
|
+
function getSkillsStorageStatus(options = {}) {
|
|
19872
|
+
return getSkillsNativeStorageStatus(options);
|
|
19873
|
+
}
|
|
19874
|
+
function getStorageStatus(options = {}) {
|
|
19875
|
+
return getSkillsNativeStorageStatus(options);
|
|
19876
|
+
}
|
|
19877
|
+
function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
19878
|
+
const projectStateDir = getProjectStateDir(targetDir);
|
|
19879
|
+
const files = [];
|
|
19880
|
+
if (existsSync12(projectStateDir)) {
|
|
19881
|
+
for (const filePath of walkFiles2(projectStateDir)) {
|
|
19882
|
+
const bytes = readFileSync11(filePath);
|
|
19883
|
+
const relativePath = toPosix(relative4(targetDir, filePath));
|
|
19884
|
+
files.push({
|
|
19885
|
+
path: relativePath,
|
|
19886
|
+
sizeBytes: bytes.byteLength,
|
|
19887
|
+
sha256: createHash2("sha256").update(bytes).digest("hex"),
|
|
19888
|
+
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
19889
|
+
});
|
|
19890
|
+
}
|
|
19891
|
+
}
|
|
19892
|
+
return {
|
|
19893
|
+
schemaVersion: 1,
|
|
19894
|
+
exportedAt: new Date().toISOString(),
|
|
19895
|
+
files: files.sort((a, b) => a.path.localeCompare(b.path))
|
|
19896
|
+
};
|
|
19897
|
+
}
|
|
19898
|
+
function importSkillsLocalSnapshot(snapshot, targetDir = process.cwd(), options = {}) {
|
|
19899
|
+
let written = 0;
|
|
19900
|
+
let skipped = 0;
|
|
19901
|
+
for (const file2 of snapshot.files) {
|
|
19902
|
+
if (!file2.contentBase64) {
|
|
19903
|
+
skipped += 1;
|
|
19904
|
+
continue;
|
|
19905
|
+
}
|
|
19906
|
+
const absolutePath = resolveSnapshotPath(targetDir, file2.path);
|
|
19907
|
+
if (existsSync12(absolutePath) && !options.overwrite) {
|
|
19908
|
+
skipped += 1;
|
|
19909
|
+
continue;
|
|
19910
|
+
}
|
|
19911
|
+
const bytes = Buffer.from(file2.contentBase64, "base64");
|
|
19912
|
+
const hash2 = createHash2("sha256").update(bytes).digest("hex");
|
|
19913
|
+
if (hash2 !== file2.sha256) {
|
|
19914
|
+
throw new Error(`Snapshot file checksum mismatch: ${file2.path}`);
|
|
19915
|
+
}
|
|
19916
|
+
mkdirSync9(dirname6(absolutePath), { recursive: true });
|
|
19917
|
+
writeFileSync8(absolutePath, bytes);
|
|
19918
|
+
written += 1;
|
|
19919
|
+
}
|
|
19920
|
+
return { written, skipped };
|
|
19921
|
+
}
|
|
19922
|
+
var skillsPostgresSyncSchemaSql = `
|
|
19923
|
+
CREATE TABLE IF NOT EXISTS skills_sync_records (
|
|
19924
|
+
scope TEXT NOT NULL,
|
|
19925
|
+
kind TEXT NOT NULL,
|
|
19926
|
+
id TEXT NOT NULL,
|
|
19927
|
+
updated_at TIMESTAMPTZ NOT NULL,
|
|
19928
|
+
deleted_at TIMESTAMPTZ,
|
|
19929
|
+
source TEXT,
|
|
19930
|
+
payload JSONB NOT NULL,
|
|
19931
|
+
PRIMARY KEY (scope, kind, id)
|
|
19932
|
+
);
|
|
19933
|
+
|
|
19934
|
+
CREATE INDEX IF NOT EXISTS skills_sync_records_updated_at_idx
|
|
19935
|
+
ON skills_sync_records (updated_at);
|
|
19936
|
+
|
|
19937
|
+
CREATE TABLE IF NOT EXISTS skills_sync_cursors (
|
|
19938
|
+
scope TEXT NOT NULL,
|
|
19939
|
+
cursor_name TEXT NOT NULL,
|
|
19940
|
+
value TEXT NOT NULL,
|
|
19941
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
19942
|
+
PRIMARY KEY (scope, cursor_name)
|
|
19943
|
+
);
|
|
19944
|
+
`.trim();
|
|
19945
|
+
|
|
19946
|
+
class SkillsPostgresSyncStore {
|
|
19947
|
+
client;
|
|
19948
|
+
constructor(client) {
|
|
19949
|
+
this.client = client;
|
|
19950
|
+
}
|
|
19951
|
+
async ensureSchema() {
|
|
19952
|
+
await this.client.query(skillsPostgresSyncSchemaSql);
|
|
19953
|
+
}
|
|
19954
|
+
async upsertRecords(records) {
|
|
19955
|
+
let count = 0;
|
|
19956
|
+
for (const record2 of records) {
|
|
19957
|
+
await this.client.query([
|
|
19958
|
+
"INSERT INTO skills_sync_records",
|
|
19959
|
+
"(scope, kind, id, updated_at, deleted_at, source, payload)",
|
|
19960
|
+
"VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)",
|
|
19961
|
+
"ON CONFLICT (scope, kind, id) DO UPDATE SET",
|
|
19962
|
+
"updated_at = EXCLUDED.updated_at,",
|
|
19963
|
+
"deleted_at = EXCLUDED.deleted_at,",
|
|
19964
|
+
"source = EXCLUDED.source,",
|
|
19965
|
+
"payload = EXCLUDED.payload"
|
|
19966
|
+
].join(" "), [
|
|
19967
|
+
record2.scope,
|
|
19968
|
+
record2.kind,
|
|
19969
|
+
record2.id,
|
|
19970
|
+
record2.updatedAt,
|
|
19971
|
+
record2.deletedAt ?? null,
|
|
19972
|
+
record2.source ?? null,
|
|
19973
|
+
JSON.stringify(record2.payload)
|
|
19974
|
+
]);
|
|
19975
|
+
count += 1;
|
|
19976
|
+
}
|
|
19977
|
+
return count;
|
|
19978
|
+
}
|
|
19979
|
+
async pullUpdatedSince(params) {
|
|
19980
|
+
const limit = params.limit ?? 500;
|
|
19981
|
+
const result = await this.client.query([
|
|
19982
|
+
"SELECT scope, kind, id, updated_at, deleted_at, source, payload",
|
|
19983
|
+
"FROM skills_sync_records",
|
|
19984
|
+
"WHERE scope = $1 AND updated_at > $2",
|
|
19985
|
+
"ORDER BY updated_at ASC",
|
|
19986
|
+
"LIMIT $3"
|
|
19987
|
+
].join(" "), [params.scope, params.since ?? "1970-01-01T00:00:00.000Z", limit]);
|
|
19988
|
+
return result.rows.map((row) => ({
|
|
19989
|
+
scope: row.scope,
|
|
19990
|
+
kind: row.kind,
|
|
19991
|
+
id: row.id,
|
|
19992
|
+
updatedAt: toIsoString(row.updated_at),
|
|
19993
|
+
deletedAt: row.deleted_at ? toIsoString(row.deleted_at) : null,
|
|
19994
|
+
source: row.source,
|
|
19995
|
+
payload: typeof row.payload === "string" ? JSON.parse(row.payload) : row.payload
|
|
19996
|
+
}));
|
|
19997
|
+
}
|
|
19998
|
+
async getCursor(scope, cursorName) {
|
|
19999
|
+
const result = await this.client.query("SELECT value FROM skills_sync_cursors WHERE scope = $1 AND cursor_name = $2", [scope, cursorName]);
|
|
20000
|
+
return result.rows[0]?.value ?? null;
|
|
20001
|
+
}
|
|
20002
|
+
async setCursor(scope, cursorName, value) {
|
|
20003
|
+
await this.client.query([
|
|
20004
|
+
"INSERT INTO skills_sync_cursors (scope, cursor_name, value, updated_at)",
|
|
20005
|
+
"VALUES ($1, $2, $3, now())",
|
|
20006
|
+
"ON CONFLICT (scope, cursor_name) DO UPDATE SET",
|
|
20007
|
+
"value = EXCLUDED.value, updated_at = EXCLUDED.updated_at"
|
|
20008
|
+
].join(" "), [scope, cursorName, value]);
|
|
20009
|
+
}
|
|
20010
|
+
}
|
|
20011
|
+
function createSkillsPostgresSyncStore(client) {
|
|
20012
|
+
return new SkillsPostgresSyncStore(client);
|
|
20013
|
+
}
|
|
20014
|
+
function createSkillsSnapshotSyncRecord(snapshot, options = {}) {
|
|
20015
|
+
return {
|
|
20016
|
+
scope: options.scope ?? "default",
|
|
20017
|
+
kind: "local-snapshot",
|
|
20018
|
+
id: options.id ?? "project-state",
|
|
20019
|
+
updatedAt: snapshot.exportedAt,
|
|
20020
|
+
source: options.source ?? "open-skills",
|
|
20021
|
+
payload: snapshot
|
|
20022
|
+
};
|
|
20023
|
+
}
|
|
20024
|
+
|
|
20025
|
+
class SkillsS3ObjectStore {
|
|
20026
|
+
options;
|
|
20027
|
+
fetchImpl;
|
|
20028
|
+
region;
|
|
20029
|
+
prefix;
|
|
20030
|
+
constructor(options) {
|
|
20031
|
+
this.options = options;
|
|
20032
|
+
this.fetchImpl = options.fetch ?? ((input, init) => fetch(input, init));
|
|
20033
|
+
this.region = options.region ?? "us-east-1";
|
|
20034
|
+
this.prefix = normalizeS3Prefix(options.prefix);
|
|
20035
|
+
}
|
|
20036
|
+
objectKey(path) {
|
|
20037
|
+
const cleaned = toPosix(path).replace(/^\.?\//, "").replace(/^\/+/, "");
|
|
20038
|
+
return [this.prefix, cleaned].filter(Boolean).join("/");
|
|
20039
|
+
}
|
|
20040
|
+
objectUrl(key) {
|
|
20041
|
+
return buildSkillsS3ObjectUrl({
|
|
20042
|
+
bucket: this.options.bucket,
|
|
20043
|
+
key,
|
|
20044
|
+
region: this.region,
|
|
20045
|
+
endpoint: this.options.endpoint,
|
|
20046
|
+
forcePathStyle: this.options.forcePathStyle
|
|
20047
|
+
});
|
|
20048
|
+
}
|
|
20049
|
+
async putObject(params) {
|
|
20050
|
+
const key = this.objectKey(params.key);
|
|
20051
|
+
const body = typeof params.body === "string" ? new TextEncoder().encode(params.body) : params.body;
|
|
20052
|
+
const url2 = this.objectUrl(key);
|
|
20053
|
+
const headers = {
|
|
20054
|
+
"content-type": params.contentType ?? "application/octet-stream",
|
|
20055
|
+
"x-amz-content-sha256": sha256Hex(body)
|
|
20056
|
+
};
|
|
20057
|
+
const signed = signSkillsAwsV4Request({
|
|
20058
|
+
method: "PUT",
|
|
20059
|
+
url: url2,
|
|
20060
|
+
region: this.region,
|
|
20061
|
+
service: "s3",
|
|
20062
|
+
headers,
|
|
20063
|
+
body,
|
|
20064
|
+
credentials: this.options.credentials
|
|
20065
|
+
});
|
|
20066
|
+
const response = await this.fetchImpl(url2, {
|
|
20067
|
+
method: "PUT",
|
|
20068
|
+
headers: signed.headers,
|
|
20069
|
+
body: toArrayBuffer(body)
|
|
20070
|
+
});
|
|
20071
|
+
if (!response.ok) {
|
|
20072
|
+
throw new Error(`S3 put failed for ${key}: ${response.status} ${response.statusText}`.trim());
|
|
20073
|
+
}
|
|
20074
|
+
return {
|
|
20075
|
+
key,
|
|
20076
|
+
url: url2,
|
|
20077
|
+
etag: response.headers.get("etag"),
|
|
20078
|
+
sizeBytes: body.byteLength
|
|
20079
|
+
};
|
|
20080
|
+
}
|
|
20081
|
+
async getObject(key) {
|
|
20082
|
+
const objectKey = this.objectKey(key);
|
|
20083
|
+
const url2 = this.objectUrl(objectKey);
|
|
20084
|
+
const signed = signSkillsAwsV4Request({
|
|
20085
|
+
method: "GET",
|
|
20086
|
+
url: url2,
|
|
20087
|
+
region: this.region,
|
|
20088
|
+
service: "s3",
|
|
20089
|
+
headers: { "x-amz-content-sha256": sha256Hex(new Uint8Array) },
|
|
20090
|
+
credentials: this.options.credentials
|
|
20091
|
+
});
|
|
20092
|
+
const response = await this.fetchImpl(url2, {
|
|
20093
|
+
method: "GET",
|
|
20094
|
+
headers: signed.headers
|
|
20095
|
+
});
|
|
20096
|
+
if (!response.ok) {
|
|
20097
|
+
throw new Error(`S3 get failed for ${objectKey}: ${response.status} ${response.statusText}`.trim());
|
|
20098
|
+
}
|
|
20099
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
20100
|
+
}
|
|
20101
|
+
}
|
|
20102
|
+
function createSkillsS3ObjectStore(options) {
|
|
20103
|
+
return new SkillsS3ObjectStore(options);
|
|
20104
|
+
}
|
|
20105
|
+
function planSkillsS3SnapshotUpload(snapshot, options = {}) {
|
|
20106
|
+
const prefix = normalizeS3Prefix(options.prefix);
|
|
20107
|
+
return snapshot.files.map((file2) => ({
|
|
20108
|
+
path: file2.path,
|
|
20109
|
+
key: [prefix, file2.path.replace(/^\.?\//, "")].filter(Boolean).join("/"),
|
|
20110
|
+
sizeBytes: file2.sizeBytes,
|
|
20111
|
+
sha256: file2.sha256
|
|
20112
|
+
}));
|
|
20113
|
+
}
|
|
20114
|
+
async function uploadSkillsSnapshotFilesToS3(snapshot, store) {
|
|
20115
|
+
const uploaded = [];
|
|
20116
|
+
for (const file2 of snapshot.files) {
|
|
20117
|
+
if (!file2.contentBase64)
|
|
20118
|
+
continue;
|
|
20119
|
+
uploaded.push(await store.putObject({
|
|
20120
|
+
key: file2.path,
|
|
20121
|
+
body: Buffer.from(file2.contentBase64, "base64"),
|
|
20122
|
+
contentType: contentTypeForPath(file2.path)
|
|
20123
|
+
}));
|
|
20124
|
+
}
|
|
20125
|
+
return uploaded;
|
|
20126
|
+
}
|
|
20127
|
+
function signSkillsAwsV4Request(options) {
|
|
20128
|
+
const now = options.now ?? new Date;
|
|
20129
|
+
const amzDate = toAmzDate(now);
|
|
20130
|
+
const dateStamp = amzDate.slice(0, 8);
|
|
20131
|
+
const url2 = new URL(options.url);
|
|
20132
|
+
const bodyBytes = typeof options.body === "string" ? new TextEncoder().encode(options.body) : options.body ?? new Uint8Array;
|
|
20133
|
+
const payloadHash = sha256Hex(bodyBytes);
|
|
20134
|
+
const headers = normalizeHeaders({
|
|
20135
|
+
...options.headers ?? {},
|
|
20136
|
+
host: url2.host,
|
|
20137
|
+
"x-amz-date": amzDate,
|
|
20138
|
+
"x-amz-content-sha256": options.headers?.["x-amz-content-sha256"] ?? payloadHash,
|
|
20139
|
+
...options.credentials.sessionToken ? { "x-amz-security-token": options.credentials.sessionToken } : {}
|
|
20140
|
+
});
|
|
20141
|
+
const signedHeaderNames = Object.keys(headers).sort();
|
|
20142
|
+
const canonicalHeaders = signedHeaderNames.map((name) => `${name}:${headers[name]}
|
|
20143
|
+
`).join("");
|
|
20144
|
+
const canonicalQuery = canonicalizeQuery(url2.searchParams);
|
|
20145
|
+
const canonicalRequest = [
|
|
20146
|
+
options.method.toUpperCase(),
|
|
20147
|
+
encodeUriPath(url2.pathname),
|
|
20148
|
+
canonicalQuery,
|
|
20149
|
+
canonicalHeaders,
|
|
20150
|
+
signedHeaderNames.join(";"),
|
|
20151
|
+
headers["x-amz-content-sha256"]
|
|
20152
|
+
].join(`
|
|
20153
|
+
`);
|
|
20154
|
+
const credentialScope = `${dateStamp}/${options.region}/${options.service}/aws4_request`;
|
|
20155
|
+
const stringToSign = [
|
|
20156
|
+
"AWS4-HMAC-SHA256",
|
|
20157
|
+
amzDate,
|
|
20158
|
+
credentialScope,
|
|
20159
|
+
sha256Hex(canonicalRequest)
|
|
20160
|
+
].join(`
|
|
20161
|
+
`);
|
|
20162
|
+
const signingKey = getAwsSigningKey(options.credentials.secretAccessKey, dateStamp, options.region, options.service);
|
|
20163
|
+
const signature = createHmac("sha256", signingKey).update(stringToSign).digest("hex");
|
|
20164
|
+
headers.authorization = [
|
|
20165
|
+
`AWS4-HMAC-SHA256 Credential=${options.credentials.accessKeyId}/${credentialScope}`,
|
|
20166
|
+
`SignedHeaders=${signedHeaderNames.join(";")}`,
|
|
20167
|
+
`Signature=${signature}`
|
|
20168
|
+
].join(", ");
|
|
20169
|
+
return { headers, canonicalRequest, stringToSign };
|
|
20170
|
+
}
|
|
20171
|
+
function buildSkillsS3ObjectUrl(params) {
|
|
20172
|
+
const region = params.region ?? "us-east-1";
|
|
20173
|
+
const key = params.key.split("/").map(encodeURIComponent).join("/");
|
|
20174
|
+
if (params.endpoint) {
|
|
20175
|
+
const endpoint = params.endpoint.replace(/\/+$/, "");
|
|
20176
|
+
return params.forcePathStyle ? `${endpoint}/${encodeURIComponent(params.bucket)}/${key}` : `${endpoint}/${key}`;
|
|
20177
|
+
}
|
|
20178
|
+
return params.forcePathStyle ? `https://s3.${region}.amazonaws.com/${encodeURIComponent(params.bucket)}/${key}` : `https://${params.bucket}.s3.${region}.amazonaws.com/${key}`;
|
|
20179
|
+
}
|
|
20180
|
+
function parseMode(value) {
|
|
20181
|
+
const normalized = value?.trim().toLowerCase();
|
|
20182
|
+
if (normalized === "remote" || normalized === "hybrid")
|
|
20183
|
+
return normalized;
|
|
20184
|
+
return "local";
|
|
20185
|
+
}
|
|
20186
|
+
function readStorageEnv(env, key) {
|
|
20187
|
+
const primaryName = SKILLS_NATIVE_STORAGE_ENV[key];
|
|
20188
|
+
const primaryValue = cleanOptional(env[primaryName]);
|
|
20189
|
+
if (primaryValue !== undefined)
|
|
20190
|
+
return { name: primaryName, value: primaryValue };
|
|
20191
|
+
const fallbackName = SKILLS_NATIVE_STORAGE_FALLBACK_ENV[key];
|
|
20192
|
+
const fallbackValue = cleanOptional(env[fallbackName]);
|
|
20193
|
+
if (fallbackValue !== undefined)
|
|
20194
|
+
return { name: fallbackName, value: fallbackValue };
|
|
20195
|
+
return { name: primaryName };
|
|
20196
|
+
}
|
|
20197
|
+
function cleanOptional(value) {
|
|
20198
|
+
const cleaned = value?.trim();
|
|
20199
|
+
return cleaned ? cleaned : undefined;
|
|
20200
|
+
}
|
|
20201
|
+
function parseBoolean(value) {
|
|
20202
|
+
if (value === undefined)
|
|
20203
|
+
return;
|
|
20204
|
+
const normalized = value.trim().toLowerCase();
|
|
20205
|
+
if (["1", "true", "yes", "on"].includes(normalized))
|
|
20206
|
+
return true;
|
|
20207
|
+
if (["0", "false", "no", "off"].includes(normalized))
|
|
20208
|
+
return false;
|
|
20209
|
+
return;
|
|
20210
|
+
}
|
|
20211
|
+
function parsePositiveInteger(value) {
|
|
20212
|
+
if (!value)
|
|
20213
|
+
return;
|
|
20214
|
+
const parsed = Number.parseInt(value, 10);
|
|
20215
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
20216
|
+
}
|
|
20217
|
+
function walkFiles2(dir) {
|
|
20218
|
+
const files = [];
|
|
20219
|
+
for (const entry of readdirSync5(dir)) {
|
|
20220
|
+
const full = join12(dir, entry);
|
|
20221
|
+
const stats = statSync4(full);
|
|
20222
|
+
if (stats.isDirectory())
|
|
20223
|
+
files.push(...walkFiles2(full));
|
|
20224
|
+
else
|
|
20225
|
+
files.push(full);
|
|
20226
|
+
}
|
|
20227
|
+
return files;
|
|
20228
|
+
}
|
|
20229
|
+
function resolveSnapshotPath(targetDir, snapshotPath) {
|
|
20230
|
+
const normalizedPath = normalize3(snapshotPath);
|
|
20231
|
+
if (normalizedPath.startsWith("..") || normalizedPath.includes(`${sep}..${sep}`) || normalizedPath.startsWith(sep)) {
|
|
20232
|
+
throw new Error(`Unsafe snapshot path: ${snapshotPath}`);
|
|
20233
|
+
}
|
|
20234
|
+
if (!toPosix(normalizedPath).startsWith(".skills/")) {
|
|
20235
|
+
throw new Error(`Snapshot path must stay inside .skills: ${snapshotPath}`);
|
|
20236
|
+
}
|
|
20237
|
+
return join12(targetDir, normalizedPath);
|
|
20238
|
+
}
|
|
20239
|
+
function normalizeS3Prefix(prefix) {
|
|
20240
|
+
return (prefix ?? "").trim().replace(/^\/+|\/+$/g, "");
|
|
20241
|
+
}
|
|
20242
|
+
function toPosix(path) {
|
|
20243
|
+
return path.split(/[\\/]+/).join("/");
|
|
20244
|
+
}
|
|
20245
|
+
function toIsoString(value) {
|
|
20246
|
+
const date5 = new Date(value);
|
|
20247
|
+
return Number.isNaN(date5.getTime()) ? value : date5.toISOString();
|
|
20248
|
+
}
|
|
20249
|
+
function sha256Hex(value) {
|
|
20250
|
+
return createHash2("sha256").update(value).digest("hex");
|
|
20251
|
+
}
|
|
20252
|
+
function normalizeHeaders(headers) {
|
|
20253
|
+
const result = {};
|
|
20254
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
20255
|
+
result[key.toLowerCase()] = String(value).trim().replace(/\s+/g, " ");
|
|
20256
|
+
}
|
|
20257
|
+
return result;
|
|
20258
|
+
}
|
|
20259
|
+
function canonicalizeQuery(params) {
|
|
20260
|
+
return [...params.entries()].sort(([aKey, aValue], [bKey, bValue]) => aKey.localeCompare(bKey) || aValue.localeCompare(bValue)).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
20261
|
+
}
|
|
20262
|
+
function encodeUriPath(pathname) {
|
|
20263
|
+
return pathname.split("/").map((segment) => encodeURIComponent(decodeURIComponent(segment)).replace(/[!'()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`)).join("/");
|
|
20264
|
+
}
|
|
20265
|
+
function toAmzDate(date5) {
|
|
20266
|
+
return date5.toISOString().replace(/[:-]|\.\d{3}/g, "");
|
|
20267
|
+
}
|
|
20268
|
+
function getAwsSigningKey(secret, dateStamp, region, service) {
|
|
20269
|
+
const kDate = createHmac("sha256", `AWS4${secret}`).update(dateStamp).digest();
|
|
20270
|
+
const kRegion = createHmac("sha256", kDate).update(region).digest();
|
|
20271
|
+
const kService = createHmac("sha256", kRegion).update(service).digest();
|
|
20272
|
+
return createHmac("sha256", kService).update("aws4_request").digest();
|
|
20273
|
+
}
|
|
20274
|
+
function contentTypeForPath(path) {
|
|
20275
|
+
const lower = path.toLowerCase();
|
|
20276
|
+
if (lower.endsWith(".json"))
|
|
20277
|
+
return "application/json";
|
|
20278
|
+
if (lower.endsWith(".log") || lower.endsWith(".txt") || lower.endsWith(".ndjson"))
|
|
20279
|
+
return "text/plain";
|
|
20280
|
+
if (lower.endsWith(".md"))
|
|
20281
|
+
return "text/markdown";
|
|
20282
|
+
if (lower.endsWith(".png"))
|
|
20283
|
+
return "image/png";
|
|
20284
|
+
if (lower.endsWith(".jpg") || lower.endsWith(".jpeg"))
|
|
20285
|
+
return "image/jpeg";
|
|
20286
|
+
if (lower.endsWith(".webp"))
|
|
20287
|
+
return "image/webp";
|
|
20288
|
+
if (lower.endsWith(".pdf"))
|
|
20289
|
+
return "application/pdf";
|
|
20290
|
+
return "application/octet-stream";
|
|
20291
|
+
}
|
|
20292
|
+
function toArrayBuffer(bytes) {
|
|
20293
|
+
const buffer = new ArrayBuffer(bytes.byteLength);
|
|
20294
|
+
new Uint8Array(buffer).set(bytes);
|
|
20295
|
+
return buffer;
|
|
20296
|
+
}
|
|
19669
20297
|
export {
|
|
19670
20298
|
writeRunLogs,
|
|
19671
20299
|
writeRegistrySyncArtifact,
|
|
@@ -19675,11 +20303,14 @@ export {
|
|
|
19675
20303
|
validatePortableSkillDirectory,
|
|
19676
20304
|
validateCron,
|
|
19677
20305
|
validateBlogArticleRunOptions,
|
|
20306
|
+
uploadSkillsSnapshotFilesToS3,
|
|
19678
20307
|
updateSkillRun,
|
|
19679
20308
|
unpinSkill,
|
|
19680
20309
|
unpinProjectSkill,
|
|
19681
20310
|
summarizeMcpToolContract,
|
|
20311
|
+
skillsPostgresSyncSchemaSql,
|
|
19682
20312
|
skillExists,
|
|
20313
|
+
signSkillsAwsV4Request,
|
|
19683
20314
|
setSkillDisabled,
|
|
19684
20315
|
setScheduleEnabled,
|
|
19685
20316
|
searchSkills,
|
|
@@ -19690,6 +20321,8 @@ export {
|
|
|
19690
20321
|
sanitizePublicDiscoveryText,
|
|
19691
20322
|
runSkill,
|
|
19692
20323
|
runPortableSkill,
|
|
20324
|
+
resolveStorageConfig,
|
|
20325
|
+
resolveSkillsNativeStorageConfig,
|
|
19693
20326
|
resolveSkillAlias,
|
|
19694
20327
|
removeSkillForAgent,
|
|
19695
20328
|
removeSkill,
|
|
@@ -19701,6 +20334,7 @@ export {
|
|
|
19701
20334
|
publicDiscoveryDocumentation,
|
|
19702
20335
|
publicDiscoveryDependencies,
|
|
19703
20336
|
portPortableSkill,
|
|
20337
|
+
planSkillsS3SnapshotUpload,
|
|
19704
20338
|
pinSkill,
|
|
19705
20339
|
pinProjectSkill,
|
|
19706
20340
|
parseSkillFrontmatter,
|
|
@@ -19729,6 +20363,16 @@ export {
|
|
|
19729
20363
|
installSkillManifest,
|
|
19730
20364
|
installSkillForAgent,
|
|
19731
20365
|
installSkill,
|
|
20366
|
+
importSkillsLocalSnapshot,
|
|
20367
|
+
getStorageStatus,
|
|
20368
|
+
getStorageMode,
|
|
20369
|
+
getStorageDatabaseUrl,
|
|
20370
|
+
getStorageDatabaseEnv,
|
|
20371
|
+
getSkillsStorageStatus,
|
|
20372
|
+
getSkillsStorageMode,
|
|
20373
|
+
getSkillsStorageDatabaseUrl,
|
|
20374
|
+
getSkillsStorageDatabaseEnv,
|
|
20375
|
+
getSkillsNativeStorageStatus,
|
|
19732
20376
|
getSkillsByTag,
|
|
19733
20377
|
getSkillsByCategory,
|
|
19734
20378
|
getSkillRunCostCents,
|
|
@@ -19770,10 +20414,14 @@ export {
|
|
|
19770
20414
|
findSkillRun,
|
|
19771
20415
|
findSimilarSkills,
|
|
19772
20416
|
findPortableSkill,
|
|
20417
|
+
exportSkillsLocalSnapshot,
|
|
19773
20418
|
ensureProjectConfig,
|
|
19774
20419
|
enableSkill,
|
|
19775
20420
|
disableSkill,
|
|
19776
20421
|
describeMcpToolContracts,
|
|
20422
|
+
createSkillsSnapshotSyncRecord,
|
|
20423
|
+
createSkillsS3ObjectStore,
|
|
20424
|
+
createSkillsPostgresSyncStore,
|
|
19777
20425
|
createSkillRun,
|
|
19778
20426
|
createSkillMcpMetadata,
|
|
19779
20427
|
createRemoteSkillsClient,
|
|
@@ -19782,11 +20430,20 @@ export {
|
|
|
19782
20430
|
createLocalSkillManifest,
|
|
19783
20431
|
completeSkillRun,
|
|
19784
20432
|
clearRegistryCache,
|
|
20433
|
+
buildSkillsS3ObjectUrl,
|
|
19785
20434
|
buildSkillsApiUrl,
|
|
19786
20435
|
appendRunEvent,
|
|
19787
20436
|
addSchedule,
|
|
20437
|
+
SkillsS3ObjectStore,
|
|
20438
|
+
SkillsPostgresSyncStore,
|
|
20439
|
+
STORAGE_TABLES,
|
|
19788
20440
|
SKILL_ALIASES,
|
|
20441
|
+
SKILLS_STORAGE_TABLES,
|
|
20442
|
+
SKILLS_STORAGE_FALLBACK_ENV,
|
|
20443
|
+
SKILLS_STORAGE_ENV,
|
|
19789
20444
|
SKILLS_PROJECT_DIR,
|
|
20445
|
+
SKILLS_NATIVE_STORAGE_FALLBACK_ENV,
|
|
20446
|
+
SKILLS_NATIVE_STORAGE_ENV,
|
|
19790
20447
|
SKILLS_CLI_MCP_PARITY,
|
|
19791
20448
|
SKILLS,
|
|
19792
20449
|
RemoteSkillsClient,
|