@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/bin/mcp.js
CHANGED
|
@@ -21797,7 +21797,7 @@ class StdioServerTransport {
|
|
|
21797
21797
|
// package.json
|
|
21798
21798
|
var package_default = {
|
|
21799
21799
|
name: "@hasna/skills",
|
|
21800
|
-
version: "0.1.
|
|
21800
|
+
version: "0.1.46",
|
|
21801
21801
|
description: "Skills library for AI coding agents",
|
|
21802
21802
|
type: "module",
|
|
21803
21803
|
bin: {
|
|
@@ -21808,6 +21808,10 @@ var package_default = {
|
|
|
21808
21808
|
".": {
|
|
21809
21809
|
import: "./dist/index.js",
|
|
21810
21810
|
types: "./dist/index.d.ts"
|
|
21811
|
+
},
|
|
21812
|
+
"./storage": {
|
|
21813
|
+
import: "./dist/storage.js",
|
|
21814
|
+
types: "./dist/storage.d.ts"
|
|
21811
21815
|
}
|
|
21812
21816
|
},
|
|
21813
21817
|
files: [
|
|
@@ -21828,7 +21832,7 @@ var package_default = {
|
|
|
21828
21832
|
types: "./dist/index.d.ts",
|
|
21829
21833
|
scripts: {
|
|
21830
21834
|
clean: "rm -rf bin/ dist/",
|
|
21831
|
-
build: "bun run clean && bun build ./src/cli/index.tsx --outdir ./bin --target bun
|
|
21835
|
+
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",
|
|
21832
21836
|
test: "bun test",
|
|
21833
21837
|
dev: "bun run ./src/cli/index.tsx",
|
|
21834
21838
|
"dev:watch": "bun --watch run ./src/cli/index.tsx",
|
|
@@ -21858,9 +21862,11 @@ var package_default = {
|
|
|
21858
21862
|
devDependencies: {
|
|
21859
21863
|
"@types/bun": "latest",
|
|
21860
21864
|
"@types/react": "^18.2.0",
|
|
21865
|
+
"react-devtools-core": "^7.0.1",
|
|
21861
21866
|
typescript: "^5"
|
|
21862
21867
|
},
|
|
21863
21868
|
dependencies: {
|
|
21869
|
+
"@hasna/events": "^0.1.3",
|
|
21864
21870
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
21865
21871
|
chalk: "^5.3.0",
|
|
21866
21872
|
commander: "^12.1.0",
|
|
@@ -30115,12 +30121,47 @@ function ensurePortableSkillFiles(skillPath, manifest) {
|
|
|
30115
30121
|
writeFileSync2(join3(skillPath, "skill.json"), renderSkillJson(next));
|
|
30116
30122
|
if (!existsSync3(join3(skillPath, "AGENTS.md")))
|
|
30117
30123
|
writeFileSync2(join3(skillPath, "AGENTS.md"), renderAgentsMd(next));
|
|
30118
|
-
|
|
30119
|
-
writeFileSync2(join3(skillPath, "package.json"), renderPackageJson(next));
|
|
30124
|
+
ensurePackageJson(skillPath, next);
|
|
30120
30125
|
if (!existsSync3(join3(skillPath, "tsconfig.json")))
|
|
30121
30126
|
writeFileSync2(join3(skillPath, "tsconfig.json"), renderTsconfig());
|
|
30122
30127
|
return readPortableSkillManifest(skillPath, next.name);
|
|
30123
30128
|
}
|
|
30129
|
+
function ensurePackageJson(skillPath, manifest) {
|
|
30130
|
+
const pkgPath = join3(skillPath, "package.json");
|
|
30131
|
+
const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
|
|
30132
|
+
const commandName = normalizePortableSkillName(first.name || manifest.name);
|
|
30133
|
+
const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
|
|
30134
|
+
if (!existsSync3(pkgPath)) {
|
|
30135
|
+
writeFileSync2(pkgPath, renderPackageJson(manifest));
|
|
30136
|
+
return;
|
|
30137
|
+
}
|
|
30138
|
+
const existing = readJsonObject(pkgPath);
|
|
30139
|
+
const bin = {};
|
|
30140
|
+
if (isRecord(existing.bin)) {
|
|
30141
|
+
for (const [name, value] of Object.entries(existing.bin)) {
|
|
30142
|
+
if (typeof value === "string" && value.trim())
|
|
30143
|
+
bin[normalizePortableSkillName(name)] = value.replace(/^\.\//, "");
|
|
30144
|
+
}
|
|
30145
|
+
} else {
|
|
30146
|
+
const binEntry = stringValue(existing.bin);
|
|
30147
|
+
if (binEntry)
|
|
30148
|
+
bin[manifest.name] = binEntry.replace(/^\.\//, "");
|
|
30149
|
+
}
|
|
30150
|
+
bin[commandName] = entry;
|
|
30151
|
+
const scripts = isRecord(existing.scripts) ? { ...existing.scripts } : {};
|
|
30152
|
+
if (!stringValue(scripts.dev))
|
|
30153
|
+
scripts.dev = `bun run ${entry}`;
|
|
30154
|
+
writeFileSync2(pkgPath, `${JSON.stringify({
|
|
30155
|
+
...existing,
|
|
30156
|
+
name: manifest.name,
|
|
30157
|
+
version: manifest.version,
|
|
30158
|
+
description: manifest.description,
|
|
30159
|
+
type: stringValue(existing.type) ?? "module",
|
|
30160
|
+
bin,
|
|
30161
|
+
scripts
|
|
30162
|
+
}, null, 2)}
|
|
30163
|
+
`);
|
|
30164
|
+
}
|
|
30124
30165
|
function copySkillDirectory(source, destination) {
|
|
30125
30166
|
mkdirSync2(destination, { recursive: true });
|
|
30126
30167
|
cpSync(source, destination, {
|
|
@@ -33297,6 +33338,46 @@ var toolContracts = [
|
|
|
33297
33338
|
inputSchema: objectSchema(),
|
|
33298
33339
|
outputSchema: objectSchema({}, [], "Setup summary.", true)
|
|
33299
33340
|
},
|
|
33341
|
+
{
|
|
33342
|
+
name: "storage_status",
|
|
33343
|
+
title: "Storage Status",
|
|
33344
|
+
description: "Show local-first storage paths and optional repo-owned Postgres/S3 readiness.",
|
|
33345
|
+
params: ["directory?"],
|
|
33346
|
+
category: "storage",
|
|
33347
|
+
sideEffects: "none",
|
|
33348
|
+
stable: true,
|
|
33349
|
+
inputSchema: objectSchema({ directory: stringSchema("Project directory.") }),
|
|
33350
|
+
outputSchema: objectSchema({
|
|
33351
|
+
package: stringSchema("Package name."),
|
|
33352
|
+
mode: { type: "string", enum: ["local", "remote", "hybrid"] },
|
|
33353
|
+
local: objectSchema({}, [], "Local storage paths.", true),
|
|
33354
|
+
remote: objectSchema({}, [], "Remote storage readiness.", true)
|
|
33355
|
+
}, ["package", "mode", "local", "remote"])
|
|
33356
|
+
},
|
|
33357
|
+
{
|
|
33358
|
+
name: "storage_sync_plan",
|
|
33359
|
+
title: "Storage Sync Plan",
|
|
33360
|
+
description: "Plan .skills snapshot sync for optional Postgres/S3 storage without network access.",
|
|
33361
|
+
params: ["directory?", "includeSchemaSql?"],
|
|
33362
|
+
category: "storage",
|
|
33363
|
+
sideEffects: "none",
|
|
33364
|
+
stable: true,
|
|
33365
|
+
inputSchema: objectSchema({
|
|
33366
|
+
directory: stringSchema("Project directory."),
|
|
33367
|
+
includeSchemaSql: { type: "boolean", default: false }
|
|
33368
|
+
}),
|
|
33369
|
+
outputSchema: objectSchema({
|
|
33370
|
+
package: stringSchema("Package name."),
|
|
33371
|
+
noNetwork: { type: "boolean", const: true },
|
|
33372
|
+
mode: { type: "string", enum: ["local", "remote", "hybrid"] },
|
|
33373
|
+
databaseConfigured: { type: "boolean" },
|
|
33374
|
+
s3Configured: { type: "boolean" },
|
|
33375
|
+
snapshotFileCount: { type: "number" },
|
|
33376
|
+
s3ObjectCount: { type: "number" },
|
|
33377
|
+
env: objectSchema({}, [], "Storage env var names.", true),
|
|
33378
|
+
schemaSql: stringSchema("Optional Postgres schema SQL.")
|
|
33379
|
+
}, ["package", "noNetwork", "mode", "databaseConfigured", "s3Configured"])
|
|
33380
|
+
},
|
|
33300
33381
|
{
|
|
33301
33382
|
name: "schedule_skill",
|
|
33302
33383
|
title: "Schedule Skill",
|
|
@@ -34923,6 +35004,266 @@ function registerScheduleTools(server) {
|
|
|
34923
35004
|
});
|
|
34924
35005
|
}
|
|
34925
35006
|
|
|
35007
|
+
// src/lib/native-storage.ts
|
|
35008
|
+
init_config();
|
|
35009
|
+
import { createHash as createHash2, createHmac } from "crypto";
|
|
35010
|
+
import {
|
|
35011
|
+
existsSync as existsSync13,
|
|
35012
|
+
mkdirSync as mkdirSync8,
|
|
35013
|
+
readFileSync as readFileSync11,
|
|
35014
|
+
readdirSync as readdirSync6,
|
|
35015
|
+
statSync as statSync5,
|
|
35016
|
+
writeFileSync as writeFileSync7
|
|
35017
|
+
} from "fs";
|
|
35018
|
+
import { dirname as dirname5, join as join13, normalize as normalize3, relative as relative3, sep } from "path";
|
|
35019
|
+
var SKILLS_STORAGE_TABLES = [
|
|
35020
|
+
"skills_sync_records",
|
|
35021
|
+
"skills_sync_cursors"
|
|
35022
|
+
];
|
|
35023
|
+
var SKILLS_NATIVE_STORAGE_ENV = {
|
|
35024
|
+
mode: "HASNA_SKILLS_STORAGE_MODE",
|
|
35025
|
+
databaseUrl: "HASNA_SKILLS_DATABASE_URL",
|
|
35026
|
+
databaseSsl: "HASNA_SKILLS_DATABASE_SSL",
|
|
35027
|
+
databaseSchema: "HASNA_SKILLS_DATABASE_SCHEMA",
|
|
35028
|
+
s3Bucket: "HASNA_SKILLS_S3_BUCKET",
|
|
35029
|
+
s3Prefix: "HASNA_SKILLS_S3_PREFIX",
|
|
35030
|
+
awsRegion: "HASNA_SKILLS_AWS_REGION",
|
|
35031
|
+
s3Endpoint: "HASNA_SKILLS_S3_ENDPOINT",
|
|
35032
|
+
s3ForcePathStyle: "HASNA_SKILLS_S3_FORCE_PATH_STYLE",
|
|
35033
|
+
s3AccessKeyId: "HASNA_SKILLS_S3_ACCESS_KEY_ID",
|
|
35034
|
+
s3SecretAccessKey: "HASNA_SKILLS_S3_SECRET_ACCESS_KEY",
|
|
35035
|
+
s3SessionToken: "HASNA_SKILLS_S3_SESSION_TOKEN",
|
|
35036
|
+
syncBatchSize: "HASNA_SKILLS_SYNC_BATCH_SIZE",
|
|
35037
|
+
dryRun: "HASNA_SKILLS_SYNC_DRY_RUN"
|
|
35038
|
+
};
|
|
35039
|
+
var SKILLS_NATIVE_STORAGE_FALLBACK_ENV = {
|
|
35040
|
+
mode: "SKILLS_STORAGE_MODE",
|
|
35041
|
+
databaseUrl: "SKILLS_DATABASE_URL",
|
|
35042
|
+
databaseSsl: "SKILLS_DATABASE_SSL",
|
|
35043
|
+
databaseSchema: "SKILLS_DATABASE_SCHEMA",
|
|
35044
|
+
s3Bucket: "SKILLS_S3_BUCKET",
|
|
35045
|
+
s3Prefix: "SKILLS_S3_PREFIX",
|
|
35046
|
+
awsRegion: "SKILLS_AWS_REGION",
|
|
35047
|
+
s3Endpoint: "SKILLS_S3_ENDPOINT",
|
|
35048
|
+
s3ForcePathStyle: "SKILLS_S3_FORCE_PATH_STYLE",
|
|
35049
|
+
s3AccessKeyId: "SKILLS_S3_ACCESS_KEY_ID",
|
|
35050
|
+
s3SecretAccessKey: "SKILLS_S3_SECRET_ACCESS_KEY",
|
|
35051
|
+
s3SessionToken: "SKILLS_S3_SESSION_TOKEN",
|
|
35052
|
+
syncBatchSize: "SKILLS_SYNC_BATCH_SIZE",
|
|
35053
|
+
dryRun: "SKILLS_SYNC_DRY_RUN"
|
|
35054
|
+
};
|
|
35055
|
+
function resolveSkillsNativeStorageConfig(env = process.env) {
|
|
35056
|
+
const mode = getSkillsStorageMode(env);
|
|
35057
|
+
return {
|
|
35058
|
+
mode,
|
|
35059
|
+
databaseUrl: getSkillsStorageDatabaseUrl(env),
|
|
35060
|
+
databaseSsl: parseBoolean(readStorageEnv(env, "databaseSsl").value),
|
|
35061
|
+
databaseSchema: readStorageEnv(env, "databaseSchema").value,
|
|
35062
|
+
s3Bucket: readStorageEnv(env, "s3Bucket").value,
|
|
35063
|
+
s3Prefix: readStorageEnv(env, "s3Prefix").value,
|
|
35064
|
+
awsRegion: readStorageEnv(env, "awsRegion").value ?? "us-east-1",
|
|
35065
|
+
s3Endpoint: readStorageEnv(env, "s3Endpoint").value,
|
|
35066
|
+
s3ForcePathStyle: parseBoolean(readStorageEnv(env, "s3ForcePathStyle").value) ?? false,
|
|
35067
|
+
syncBatchSize: parsePositiveInteger(readStorageEnv(env, "syncBatchSize").value) ?? 500,
|
|
35068
|
+
dryRun: parseBoolean(readStorageEnv(env, "dryRun").value) ?? true
|
|
35069
|
+
};
|
|
35070
|
+
}
|
|
35071
|
+
function resolveStorageConfig(env = process.env) {
|
|
35072
|
+
return resolveSkillsNativeStorageConfig(env);
|
|
35073
|
+
}
|
|
35074
|
+
function getSkillsStorageMode(env = process.env) {
|
|
35075
|
+
return parseMode(readStorageEnv(env, "mode").value);
|
|
35076
|
+
}
|
|
35077
|
+
function getSkillsStorageDatabaseUrl(env = process.env) {
|
|
35078
|
+
return readStorageEnv(env, "databaseUrl").value;
|
|
35079
|
+
}
|
|
35080
|
+
function getSkillsNativeStorageStatus(options = {}) {
|
|
35081
|
+
const env = options.env ?? process.env;
|
|
35082
|
+
const config2 = resolveSkillsNativeStorageConfig(env);
|
|
35083
|
+
const modeEnv = readStorageEnv(env, "mode");
|
|
35084
|
+
const databaseEnv = readStorageEnv(env, "databaseUrl");
|
|
35085
|
+
const s3BucketEnv = readStorageEnv(env, "s3Bucket");
|
|
35086
|
+
const targetDir = options.targetDir ?? process.cwd();
|
|
35087
|
+
return {
|
|
35088
|
+
package: "open-skills",
|
|
35089
|
+
mode: config2.mode,
|
|
35090
|
+
tables: [...SKILLS_STORAGE_TABLES],
|
|
35091
|
+
env: {
|
|
35092
|
+
mode: SKILLS_NATIVE_STORAGE_ENV.mode,
|
|
35093
|
+
databaseUrl: SKILLS_NATIVE_STORAGE_ENV.databaseUrl,
|
|
35094
|
+
s3Bucket: SKILLS_NATIVE_STORAGE_ENV.s3Bucket
|
|
35095
|
+
},
|
|
35096
|
+
local: {
|
|
35097
|
+
dataDir: getDataDir(),
|
|
35098
|
+
projectStateDir: getProjectStateDir(targetDir),
|
|
35099
|
+
feedbackDbPath: join13(getDataDir(), "skills.db")
|
|
35100
|
+
},
|
|
35101
|
+
remote: {
|
|
35102
|
+
databaseConfigured: Boolean(config2.databaseUrl),
|
|
35103
|
+
s3Configured: Boolean(config2.s3Bucket),
|
|
35104
|
+
databaseEnv: SKILLS_NATIVE_STORAGE_ENV.databaseUrl,
|
|
35105
|
+
s3BucketEnv: SKILLS_NATIVE_STORAGE_ENV.s3Bucket,
|
|
35106
|
+
activeModeEnv: modeEnv.name,
|
|
35107
|
+
activeDatabaseEnv: databaseEnv.name,
|
|
35108
|
+
activeS3BucketEnv: s3BucketEnv.name,
|
|
35109
|
+
region: config2.awsRegion ?? "us-east-1",
|
|
35110
|
+
dryRun: config2.dryRun
|
|
35111
|
+
}
|
|
35112
|
+
};
|
|
35113
|
+
}
|
|
35114
|
+
function getStorageStatus(options = {}) {
|
|
35115
|
+
return getSkillsNativeStorageStatus(options);
|
|
35116
|
+
}
|
|
35117
|
+
function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
35118
|
+
const projectStateDir = getProjectStateDir(targetDir);
|
|
35119
|
+
const files = [];
|
|
35120
|
+
if (existsSync13(projectStateDir)) {
|
|
35121
|
+
for (const filePath of walkFiles2(projectStateDir)) {
|
|
35122
|
+
const bytes = readFileSync11(filePath);
|
|
35123
|
+
const relativePath = toPosix(relative3(targetDir, filePath));
|
|
35124
|
+
files.push({
|
|
35125
|
+
path: relativePath,
|
|
35126
|
+
sizeBytes: bytes.byteLength,
|
|
35127
|
+
sha256: createHash2("sha256").update(bytes).digest("hex"),
|
|
35128
|
+
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
35129
|
+
});
|
|
35130
|
+
}
|
|
35131
|
+
}
|
|
35132
|
+
return {
|
|
35133
|
+
schemaVersion: 1,
|
|
35134
|
+
exportedAt: new Date().toISOString(),
|
|
35135
|
+
files: files.sort((a, b) => a.path.localeCompare(b.path))
|
|
35136
|
+
};
|
|
35137
|
+
}
|
|
35138
|
+
var skillsPostgresSyncSchemaSql = `
|
|
35139
|
+
CREATE TABLE IF NOT EXISTS skills_sync_records (
|
|
35140
|
+
scope TEXT NOT NULL,
|
|
35141
|
+
kind TEXT NOT NULL,
|
|
35142
|
+
id TEXT NOT NULL,
|
|
35143
|
+
updated_at TIMESTAMPTZ NOT NULL,
|
|
35144
|
+
deleted_at TIMESTAMPTZ,
|
|
35145
|
+
source TEXT,
|
|
35146
|
+
payload JSONB NOT NULL,
|
|
35147
|
+
PRIMARY KEY (scope, kind, id)
|
|
35148
|
+
);
|
|
35149
|
+
|
|
35150
|
+
CREATE INDEX IF NOT EXISTS skills_sync_records_updated_at_idx
|
|
35151
|
+
ON skills_sync_records (updated_at);
|
|
35152
|
+
|
|
35153
|
+
CREATE TABLE IF NOT EXISTS skills_sync_cursors (
|
|
35154
|
+
scope TEXT NOT NULL,
|
|
35155
|
+
cursor_name TEXT NOT NULL,
|
|
35156
|
+
value TEXT NOT NULL,
|
|
35157
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
35158
|
+
PRIMARY KEY (scope, cursor_name)
|
|
35159
|
+
);
|
|
35160
|
+
`.trim();
|
|
35161
|
+
function planSkillsS3SnapshotUpload(snapshot, options = {}) {
|
|
35162
|
+
const prefix = normalizeS3Prefix(options.prefix);
|
|
35163
|
+
return snapshot.files.map((file2) => ({
|
|
35164
|
+
path: file2.path,
|
|
35165
|
+
key: [prefix, file2.path.replace(/^\.?\//, "")].filter(Boolean).join("/"),
|
|
35166
|
+
sizeBytes: file2.sizeBytes,
|
|
35167
|
+
sha256: file2.sha256
|
|
35168
|
+
}));
|
|
35169
|
+
}
|
|
35170
|
+
function parseMode(value) {
|
|
35171
|
+
const normalized = value?.trim().toLowerCase();
|
|
35172
|
+
if (normalized === "remote" || normalized === "hybrid")
|
|
35173
|
+
return normalized;
|
|
35174
|
+
return "local";
|
|
35175
|
+
}
|
|
35176
|
+
function readStorageEnv(env, key) {
|
|
35177
|
+
const primaryName = SKILLS_NATIVE_STORAGE_ENV[key];
|
|
35178
|
+
const primaryValue = cleanOptional(env[primaryName]);
|
|
35179
|
+
if (primaryValue !== undefined)
|
|
35180
|
+
return { name: primaryName, value: primaryValue };
|
|
35181
|
+
const fallbackName = SKILLS_NATIVE_STORAGE_FALLBACK_ENV[key];
|
|
35182
|
+
const fallbackValue = cleanOptional(env[fallbackName]);
|
|
35183
|
+
if (fallbackValue !== undefined)
|
|
35184
|
+
return { name: fallbackName, value: fallbackValue };
|
|
35185
|
+
return { name: primaryName };
|
|
35186
|
+
}
|
|
35187
|
+
function cleanOptional(value) {
|
|
35188
|
+
const cleaned = value?.trim();
|
|
35189
|
+
return cleaned ? cleaned : undefined;
|
|
35190
|
+
}
|
|
35191
|
+
function parseBoolean(value) {
|
|
35192
|
+
if (value === undefined)
|
|
35193
|
+
return;
|
|
35194
|
+
const normalized = value.trim().toLowerCase();
|
|
35195
|
+
if (["1", "true", "yes", "on"].includes(normalized))
|
|
35196
|
+
return true;
|
|
35197
|
+
if (["0", "false", "no", "off"].includes(normalized))
|
|
35198
|
+
return false;
|
|
35199
|
+
return;
|
|
35200
|
+
}
|
|
35201
|
+
function parsePositiveInteger(value) {
|
|
35202
|
+
if (!value)
|
|
35203
|
+
return;
|
|
35204
|
+
const parsed = Number.parseInt(value, 10);
|
|
35205
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
35206
|
+
}
|
|
35207
|
+
function walkFiles2(dir) {
|
|
35208
|
+
const files = [];
|
|
35209
|
+
for (const entry of readdirSync6(dir)) {
|
|
35210
|
+
const full = join13(dir, entry);
|
|
35211
|
+
const stats = statSync5(full);
|
|
35212
|
+
if (stats.isDirectory())
|
|
35213
|
+
files.push(...walkFiles2(full));
|
|
35214
|
+
else
|
|
35215
|
+
files.push(full);
|
|
35216
|
+
}
|
|
35217
|
+
return files;
|
|
35218
|
+
}
|
|
35219
|
+
function normalizeS3Prefix(prefix) {
|
|
35220
|
+
return (prefix ?? "").trim().replace(/^\/+|\/+$/g, "");
|
|
35221
|
+
}
|
|
35222
|
+
function toPosix(path) {
|
|
35223
|
+
return path.split(/[\\/]+/).join("/");
|
|
35224
|
+
}
|
|
35225
|
+
|
|
35226
|
+
// src/mcp/storage-tools.ts
|
|
35227
|
+
function registerStorageTools(server) {
|
|
35228
|
+
server.registerTool("storage_status", {
|
|
35229
|
+
title: "Storage Status",
|
|
35230
|
+
description: "Show local-first storage paths and optional repo-owned Postgres/S3 readiness.",
|
|
35231
|
+
inputSchema: {
|
|
35232
|
+
directory: exports_external.string().optional()
|
|
35233
|
+
}
|
|
35234
|
+
}, async ({ directory }) => {
|
|
35235
|
+
return mcpJson(getStorageStatus({ targetDir: directory || process.cwd() }), true);
|
|
35236
|
+
});
|
|
35237
|
+
server.registerTool("storage_sync_plan", {
|
|
35238
|
+
title: "Storage Sync Plan",
|
|
35239
|
+
description: "Plan .skills snapshot sync for optional Postgres/S3 storage without network access.",
|
|
35240
|
+
inputSchema: {
|
|
35241
|
+
directory: exports_external.string().optional(),
|
|
35242
|
+
includeSchemaSql: exports_external.boolean().optional()
|
|
35243
|
+
}
|
|
35244
|
+
}, async ({ directory, includeSchemaSql }) => {
|
|
35245
|
+
const targetDir = directory || process.cwd();
|
|
35246
|
+
const config2 = resolveStorageConfig();
|
|
35247
|
+
const snapshot = exportSkillsLocalSnapshot(targetDir, { includeFileContents: false });
|
|
35248
|
+
const s3Plan = config2.s3Bucket ? planSkillsS3SnapshotUpload(snapshot, { prefix: config2.s3Prefix }) : [];
|
|
35249
|
+
return mcpJson({
|
|
35250
|
+
package: "open-skills",
|
|
35251
|
+
noNetwork: true,
|
|
35252
|
+
mode: config2.mode,
|
|
35253
|
+
databaseConfigured: Boolean(config2.databaseUrl),
|
|
35254
|
+
s3Configured: Boolean(config2.s3Bucket),
|
|
35255
|
+
snapshotFileCount: snapshot.files.length,
|
|
35256
|
+
s3ObjectCount: s3Plan.length,
|
|
35257
|
+
env: {
|
|
35258
|
+
mode: SKILLS_NATIVE_STORAGE_ENV.mode,
|
|
35259
|
+
databaseUrl: SKILLS_NATIVE_STORAGE_ENV.databaseUrl,
|
|
35260
|
+
s3Bucket: SKILLS_NATIVE_STORAGE_ENV.s3Bucket
|
|
35261
|
+
},
|
|
35262
|
+
...includeSchemaSql ? { schemaSql: skillsPostgresSyncSchemaSql } : {}
|
|
35263
|
+
}, true);
|
|
35264
|
+
});
|
|
35265
|
+
}
|
|
35266
|
+
|
|
34926
35267
|
// src/mcp/server.ts
|
|
34927
35268
|
function buildServer() {
|
|
34928
35269
|
const server = new McpServer({
|
|
@@ -34932,6 +35273,7 @@ function buildServer() {
|
|
|
34932
35273
|
registerDiscoveryTools(server);
|
|
34933
35274
|
registerOperationTools(server);
|
|
34934
35275
|
registerScheduleTools(server);
|
|
35276
|
+
registerStorageTools(server);
|
|
34935
35277
|
registerResourceMetaTools(server);
|
|
34936
35278
|
return server;
|
|
34937
35279
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -25,5 +25,6 @@ export { SKILLS_CLI_MCP_PARITY, findSkillsParityForCliCommand, findSkillsParityF
|
|
|
25
25
|
export { createRegistrySyncArtifact, writeRegistrySyncArtifact, type RegistrySyncArtifact, type RegistrySyncOptions, type RegistrySyncSkill, } from "./lib/registry-sync.js";
|
|
26
26
|
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";
|
|
27
27
|
export { getFeedbackDbPath, saveFeedback, type FeedbackCategory, type FeedbackInput, type FeedbackResult, } from "./lib/feedback.js";
|
|
28
|
+
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, getSkillsStorageMode, getSkillsStorageStatus, getStorageDatabaseEnv, getStorageDatabaseUrl, getStorageMode, 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 SkillsStorageMode, type SkillsStorageTable, type SkillsSyncRecord, } from "./lib/native-storage.js";
|
|
28
29
|
export { SKILL_ALIASES, normalizeSkillSlug, resolveSkillAlias, type SkillAlias, } from "./lib/skill-aliases.js";
|
|
29
30
|
export type { SkillResponse, SkillDetailResponse, CategoryResponse, TagResponse, InstallResponse, RemoveResponse, VersionResponse, ExportResponse, ImportResponse, SearchResponse, CategoryInstallResponse, ErrorResponse, } from "./types/api.js";
|