@hasna/skills 0.1.63 → 0.1.64
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 +28 -6
- package/bin/index.js +1593 -228
- package/bin/mcp.js +290 -24
- package/bin/migrate.js +229 -33
- package/bin/server.js +774 -116
- package/bin/worker.js +558 -79
- package/dist/cli/commands/registry-reconcile.d.ts +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +559 -251
- package/dist/lib/agent-sync.d.ts +26 -6
- package/dist/lib/auth-store.d.ts +37 -0
- package/dist/lib/config.d.ts +51 -0
- package/dist/lib/home-census.d.ts +4 -0
- package/dist/lib/home-migration.d.ts +8 -9
- package/dist/lib/native-storage.d.ts +1 -1
- package/dist/lib/portable-skills.d.ts +35 -6
- package/dist/lib/pull.d.ts +31 -0
- package/dist/lib/registry-reconcile.d.ts +114 -0
- package/dist/lib/registry.d.ts +7 -4
- package/dist/lib/remote-client.d.ts +118 -1
- package/dist/lib/remote-registry.d.ts +26 -0
- package/dist/lib/revision.d.ts +29 -0
- package/dist/sdk/index.js +1351 -353
- package/dist/server/app.d.ts +1 -1
- package/dist/server/config.d.ts +12 -2
- package/dist/server/rows.d.ts +2 -1
- package/dist/server/skills-api.d.ts +108 -6
- package/dist/server/sqlite-store.d.ts +20 -3
- package/dist/server/store.d.ts +31 -5
- package/dist/server/types.d.ts +98 -3
- package/dist/storage.js +7 -2
- package/migrations/postgres/0004_hosted_pins.sql +28 -0
- package/migrations/postgres/0005_revision_tombstone_registry.sql +37 -0
- package/migrations/postgres/0005_tag_projection.sql +36 -0
- package/migrations/sqlite/0004_hosted_pins.sql +21 -0
- package/migrations/sqlite/0005_revision_tombstone_registry.sql +18 -0
- package/migrations/sqlite/0005_tag_projection.sql +25 -0
- package/package.json +3 -2
package/bin/mcp.js
CHANGED
|
@@ -6727,6 +6727,9 @@ function normalizeConfigValue(key, value) {
|
|
|
6727
6727
|
return value.trim() ? value : undefined;
|
|
6728
6728
|
return;
|
|
6729
6729
|
}
|
|
6730
|
+
function isOwnerLayoutMigrated(appDir) {
|
|
6731
|
+
return existsSync(join(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD));
|
|
6732
|
+
}
|
|
6730
6733
|
function getDataDir() {
|
|
6731
6734
|
const override = process.env[DATA_DIR_ENV];
|
|
6732
6735
|
if (override) {
|
|
@@ -6750,6 +6753,33 @@ function getDataDir() {
|
|
|
6750
6753
|
}
|
|
6751
6754
|
return newDir;
|
|
6752
6755
|
}
|
|
6756
|
+
function getDataDirReadOnly() {
|
|
6757
|
+
const override = process.env[DATA_DIR_ENV];
|
|
6758
|
+
if (override)
|
|
6759
|
+
return override;
|
|
6760
|
+
return join(process.env["HOME"] || process.env["USERPROFILE"] || homedir(), ".hasna", "skills");
|
|
6761
|
+
}
|
|
6762
|
+
function getConfigPathReadOnly(scope) {
|
|
6763
|
+
if (scope === "global")
|
|
6764
|
+
return join(getDataDirReadOnly(), "config.json");
|
|
6765
|
+
return join(process.cwd(), "skills.config.json");
|
|
6766
|
+
}
|
|
6767
|
+
function loadConfigReadOnly() {
|
|
6768
|
+
const canonicalConfigPath = getConfigPathReadOnly("global");
|
|
6769
|
+
let globalConfig2;
|
|
6770
|
+
if (existsSync(canonicalConfigPath)) {
|
|
6771
|
+
globalConfig2 = readConfigFile(canonicalConfigPath);
|
|
6772
|
+
} else if (process.env[DATA_DIR_ENV] !== undefined) {
|
|
6773
|
+
globalConfig2 = {};
|
|
6774
|
+
} else {
|
|
6775
|
+
globalConfig2 = readConfigFile(legacyConfigFilePath());
|
|
6776
|
+
}
|
|
6777
|
+
const projectConfig = readConfigFile(getConfigPathReadOnly("project"));
|
|
6778
|
+
return { ...globalConfig2, ...projectConfig };
|
|
6779
|
+
}
|
|
6780
|
+
function legacyConfigFilePath() {
|
|
6781
|
+
return join(process.env["HOME"] || process.env["USERPROFILE"] || homedir(), ".skillsrc");
|
|
6782
|
+
}
|
|
6753
6783
|
function getConfigPath(scope) {
|
|
6754
6784
|
if (scope === "global") {
|
|
6755
6785
|
return join(getDataDir(), "config.json");
|
|
@@ -6781,7 +6811,7 @@ function loadConfig() {
|
|
|
6781
6811
|
const projectConfig = readConfigFile(getConfigPath("project"));
|
|
6782
6812
|
return { ...globalConfig2, ...projectConfig };
|
|
6783
6813
|
}
|
|
6784
|
-
var ENUM_KEYS, STRING_KEYS, DATA_DIR_ENV = "HASNA_SKILLS_DIR", INSTALLED_SKILLS_DIRNAME = "installed";
|
|
6814
|
+
var ENUM_KEYS, STRING_KEYS, DATA_DIR_ENV = "HASNA_SKILLS_DIR", INSTALLED_SKILLS_DIRNAME = "installed", SKILLS_CACHE_DIRNAME = "skills", LAYOUT_MIGRATION_RECORD = ".layout-migration.json";
|
|
6785
6815
|
var init_config = __esm(() => {
|
|
6786
6816
|
init_retired_settings();
|
|
6787
6817
|
ENUM_KEYS = {
|
|
@@ -6866,19 +6896,33 @@ var exports_auth_store = {};
|
|
|
6866
6896
|
__export(exports_auth_store, {
|
|
6867
6897
|
saveAuthConfig: () => saveAuthConfig,
|
|
6868
6898
|
normalizeSkillsApiOrigin: () => normalizeSkillsApiOrigin,
|
|
6899
|
+
getAuthFilePathReadOnly: () => getAuthFilePathReadOnly,
|
|
6900
|
+
getAuthFilePath: () => getAuthFilePath,
|
|
6901
|
+
getAuthConfigReadOnly: () => getAuthConfigReadOnly,
|
|
6869
6902
|
getAuthConfig: () => getAuthConfig,
|
|
6870
6903
|
getApiUrl: () => getApiUrl,
|
|
6904
|
+
getApiKeyReadOnly: () => getApiKeyReadOnly,
|
|
6871
6905
|
getApiKey: () => getApiKey,
|
|
6872
6906
|
clearAuthConfig: () => clearAuthConfig
|
|
6873
6907
|
});
|
|
6874
6908
|
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync6, unlinkSync } from "fs";
|
|
6875
|
-
import { join as join11 } from "path";
|
|
6909
|
+
import { dirname as dirname5, join as join11 } from "path";
|
|
6876
6910
|
import { homedir as homedir3 } from "os";
|
|
6911
|
+
function getAuthFilePath() {
|
|
6912
|
+
return join11(getDataDir(), "auth.json");
|
|
6913
|
+
}
|
|
6914
|
+
function getAuthFilePathReadOnly() {
|
|
6915
|
+
return join11(getDataDirReadOnly(), "auth.json");
|
|
6916
|
+
}
|
|
6917
|
+
function legacyAuthFilePath() {
|
|
6918
|
+
return join11(process.env["HOME"] || process.env["USERPROFILE"] || homedir3(), ".skills", "auth.json");
|
|
6919
|
+
}
|
|
6877
6920
|
function getAuthConfig() {
|
|
6878
6921
|
if (cachedConfig !== undefined)
|
|
6879
6922
|
return cachedConfig;
|
|
6880
6923
|
try {
|
|
6881
|
-
const
|
|
6924
|
+
const file = existsSync11(getAuthFilePath()) ? getAuthFilePath() : legacyAuthFilePath();
|
|
6925
|
+
const raw = readFileSync10(file, "utf-8");
|
|
6882
6926
|
const config2 = JSON.parse(raw);
|
|
6883
6927
|
if (!config2.apiKey) {
|
|
6884
6928
|
cachedConfig = null;
|
|
@@ -6892,19 +6936,20 @@ function getAuthConfig() {
|
|
|
6892
6936
|
}
|
|
6893
6937
|
}
|
|
6894
6938
|
function saveAuthConfig(config2) {
|
|
6895
|
-
|
|
6896
|
-
|
|
6939
|
+
const file = getAuthFilePath();
|
|
6940
|
+
mkdirSync6(dirname5(file), { recursive: true, mode: 448 });
|
|
6941
|
+
writeFileSync6(file, JSON.stringify(config2, null, 2) + `
|
|
6897
6942
|
`, { mode: 384 });
|
|
6898
6943
|
cachedConfig = config2;
|
|
6899
6944
|
}
|
|
6900
6945
|
function clearAuthConfig() {
|
|
6901
6946
|
try {
|
|
6902
|
-
unlinkSync(
|
|
6947
|
+
unlinkSync(getAuthFilePath());
|
|
6903
6948
|
} catch {}
|
|
6904
6949
|
try {
|
|
6905
|
-
unlinkSync(
|
|
6950
|
+
unlinkSync(legacyAuthFilePath());
|
|
6906
6951
|
} catch {}
|
|
6907
|
-
cachedConfig =
|
|
6952
|
+
cachedConfig = undefined;
|
|
6908
6953
|
}
|
|
6909
6954
|
function getApiKey() {
|
|
6910
6955
|
if (process.env.SKILLS_API_KEY)
|
|
@@ -6913,6 +6958,25 @@ function getApiKey() {
|
|
|
6913
6958
|
return process.env.SKILL_API_KEY;
|
|
6914
6959
|
return getAuthConfig()?.apiKey || null;
|
|
6915
6960
|
}
|
|
6961
|
+
function getAuthConfigReadOnly() {
|
|
6962
|
+
try {
|
|
6963
|
+
const file = existsSync11(getAuthFilePathReadOnly()) ? getAuthFilePathReadOnly() : legacyAuthFilePath();
|
|
6964
|
+
const raw = readFileSync10(file, "utf-8");
|
|
6965
|
+
const config2 = JSON.parse(raw);
|
|
6966
|
+
if (!config2.apiKey)
|
|
6967
|
+
return null;
|
|
6968
|
+
return config2;
|
|
6969
|
+
} catch {
|
|
6970
|
+
return null;
|
|
6971
|
+
}
|
|
6972
|
+
}
|
|
6973
|
+
function getApiKeyReadOnly() {
|
|
6974
|
+
if (process.env.SKILLS_API_KEY)
|
|
6975
|
+
return process.env.SKILLS_API_KEY;
|
|
6976
|
+
if (process.env.SKILL_API_KEY)
|
|
6977
|
+
return process.env.SKILL_API_KEY;
|
|
6978
|
+
return getAuthConfigReadOnly()?.apiKey || null;
|
|
6979
|
+
}
|
|
6916
6980
|
function normalizeSkillsApiOrigin(apiUrl) {
|
|
6917
6981
|
const url = new URL(apiUrl);
|
|
6918
6982
|
const pathname = url.pathname.replace(/\/+$/, "");
|
|
@@ -6928,12 +6992,10 @@ function normalizeSkillsApiOrigin(apiUrl) {
|
|
|
6928
6992
|
function getApiUrl(action) {
|
|
6929
6993
|
return normalizeSkillsApiOrigin(requireApiUrl(action));
|
|
6930
6994
|
}
|
|
6931
|
-
var
|
|
6995
|
+
var cachedConfig;
|
|
6932
6996
|
var init_auth_store = __esm(() => {
|
|
6933
6997
|
init_api_url();
|
|
6934
|
-
|
|
6935
|
-
AUTH_FILE = join11(AUTH_DIR, "auth.json");
|
|
6936
|
-
LEGACY_AUTH_FILE = join11(homedir3(), ".skills", "auth.json");
|
|
6998
|
+
init_config();
|
|
6937
6999
|
});
|
|
6938
7000
|
|
|
6939
7001
|
// src/lib/blog-article.ts
|
|
@@ -7069,8 +7131,11 @@ var init_blog_article = __esm(() => {
|
|
|
7069
7131
|
// src/lib/remote-client.ts
|
|
7070
7132
|
var exports_remote_client = {};
|
|
7071
7133
|
__export(exports_remote_client, {
|
|
7134
|
+
createRemoteSkillsClientReadOnly: () => createRemoteSkillsClientReadOnly,
|
|
7072
7135
|
createRemoteSkillsClient: () => createRemoteSkillsClient,
|
|
7073
|
-
RemoteSkillsClient: () => RemoteSkillsClient
|
|
7136
|
+
RemoteSkillsClient: () => RemoteSkillsClient,
|
|
7137
|
+
RemoteRouteUnsupportedError: () => RemoteRouteUnsupportedError,
|
|
7138
|
+
RemoteRequestError: () => RemoteRequestError
|
|
7074
7139
|
});
|
|
7075
7140
|
|
|
7076
7141
|
class RemoteSkillsClient {
|
|
@@ -7090,6 +7155,20 @@ class RemoteSkillsClient {
|
|
|
7090
7155
|
}
|
|
7091
7156
|
});
|
|
7092
7157
|
}
|
|
7158
|
+
async requestNewRoute(path, options, opts = {}) {
|
|
7159
|
+
const response = await this.request(path, options);
|
|
7160
|
+
const routePath = path.split("?")[0];
|
|
7161
|
+
if (response.status === 404 || response.status === 405) {
|
|
7162
|
+
if (response.status === 404 && opts.domainNotFoundCodes?.length && await responseBodyCarriesCode(response, opts.domainNotFoundCodes)) {
|
|
7163
|
+
return response;
|
|
7164
|
+
}
|
|
7165
|
+
throw new RemoteRouteUnsupportedError(routePath, response.status, this.apiUrl);
|
|
7166
|
+
}
|
|
7167
|
+
if (!response.ok) {
|
|
7168
|
+
throw new RemoteRequestError(routePath, response.status, response.statusText);
|
|
7169
|
+
}
|
|
7170
|
+
return response;
|
|
7171
|
+
}
|
|
7093
7172
|
async listSkills() {
|
|
7094
7173
|
const res = await this.request("/api/v1/skills");
|
|
7095
7174
|
return res.json();
|
|
@@ -7106,6 +7185,14 @@ class RemoteSkillsClient {
|
|
|
7106
7185
|
return null;
|
|
7107
7186
|
return res.json();
|
|
7108
7187
|
}
|
|
7188
|
+
async getSkillStatus(slug) {
|
|
7189
|
+
const res = await this.request(`/api/v1/skills/${encodeURIComponent(slug)}`, { method: "GET" });
|
|
7190
|
+
let body = null;
|
|
7191
|
+
try {
|
|
7192
|
+
body = await res.json();
|
|
7193
|
+
} catch {}
|
|
7194
|
+
return { status: res.status, body };
|
|
7195
|
+
}
|
|
7109
7196
|
async submitRun(slug, input, args) {
|
|
7110
7197
|
const res = await this.request(`/api/v1/runs/${slug}`, {
|
|
7111
7198
|
method: "POST",
|
|
@@ -7139,15 +7226,18 @@ class RemoteSkillsClient {
|
|
|
7139
7226
|
method: "GET"
|
|
7140
7227
|
});
|
|
7141
7228
|
}
|
|
7142
|
-
async publishSkill(manifest, bundle) {
|
|
7229
|
+
async publishSkill(manifest, bundle, ifMatch) {
|
|
7143
7230
|
const form = new FormData;
|
|
7144
7231
|
form.set("manifest", JSON.stringify(manifest));
|
|
7145
7232
|
if (bundle) {
|
|
7146
7233
|
form.set("bundle", new Blob([bundle], { type: "application/gzip" }), `${String(manifest.slug ?? "skill")}.tar.gz`);
|
|
7147
7234
|
}
|
|
7235
|
+
const headers = { Authorization: `Bearer ${this.apiKey}` };
|
|
7236
|
+
if (ifMatch)
|
|
7237
|
+
headers["If-Match"] = ifMatch;
|
|
7148
7238
|
return fetch(`${this.apiUrl}/api/v1/skills`, {
|
|
7149
7239
|
method: "POST",
|
|
7150
|
-
headers
|
|
7240
|
+
headers,
|
|
7151
7241
|
body: form
|
|
7152
7242
|
});
|
|
7153
7243
|
}
|
|
@@ -7163,6 +7253,135 @@ class RemoteSkillsClient {
|
|
|
7163
7253
|
return null;
|
|
7164
7254
|
return response;
|
|
7165
7255
|
}
|
|
7256
|
+
async listPins() {
|
|
7257
|
+
const response = await this.requestNewRoute("/api/v1/pins");
|
|
7258
|
+
return normalizePinList(await response.json());
|
|
7259
|
+
}
|
|
7260
|
+
async pin(slug, metadata) {
|
|
7261
|
+
const path = `/api/v1/pins/${encodeURIComponent(slug)}`;
|
|
7262
|
+
const response = await this.requestNewRoute(path, {
|
|
7263
|
+
method: "PUT",
|
|
7264
|
+
body: JSON.stringify({ ...metadata ? { metadata } : {} })
|
|
7265
|
+
});
|
|
7266
|
+
return normalizePin(await response.json());
|
|
7267
|
+
}
|
|
7268
|
+
async unpin(slug) {
|
|
7269
|
+
const path = `/api/v1/pins/${encodeURIComponent(slug)}`;
|
|
7270
|
+
const response = await this.requestNewRoute(path, { method: "DELETE" }, { domainNotFoundCodes: ["PIN_NOT_FOUND"] });
|
|
7271
|
+
return response.status !== 404;
|
|
7272
|
+
}
|
|
7273
|
+
async listTags() {
|
|
7274
|
+
const response = await this.requestNewRoute("/api/v1/tags");
|
|
7275
|
+
const payload = await response.json();
|
|
7276
|
+
if (!Array.isArray(payload)) {
|
|
7277
|
+
throw new Error("Remote tags payload did not match the expected contract (expected an array of tag names)");
|
|
7278
|
+
}
|
|
7279
|
+
for (const tag of payload) {
|
|
7280
|
+
if (typeof tag !== "string" || tag.trim().length === 0) {
|
|
7281
|
+
throw new Error("Remote tags payload did not match the expected contract (every element must be a non-empty tag name)");
|
|
7282
|
+
}
|
|
7283
|
+
}
|
|
7284
|
+
return payload;
|
|
7285
|
+
}
|
|
7286
|
+
async skillsByTag(tag) {
|
|
7287
|
+
const path = `/api/v1/tags/${encodeURIComponent(tag)}/skills`;
|
|
7288
|
+
const response = await this.requestNewRoute(path);
|
|
7289
|
+
return normalizeSkillSummaryList(await response.json());
|
|
7290
|
+
}
|
|
7291
|
+
async listUpdatedSince(since, options = {}) {
|
|
7292
|
+
const params = new URLSearchParams({ since });
|
|
7293
|
+
if (options.cursor)
|
|
7294
|
+
params.set("cursor", options.cursor);
|
|
7295
|
+
if (options.limit !== undefined)
|
|
7296
|
+
params.set("limit", String(options.limit));
|
|
7297
|
+
const response = await this.requestNewRoute(`/api/v1/skills/updated?${params.toString()}`);
|
|
7298
|
+
return normalizeUpdatedSincePage(await response.json());
|
|
7299
|
+
}
|
|
7300
|
+
}
|
|
7301
|
+
function requireOptionalString(record3, field) {
|
|
7302
|
+
if (record3[field] === undefined)
|
|
7303
|
+
return;
|
|
7304
|
+
if (typeof record3[field] !== "string") {
|
|
7305
|
+
throw new Error(`Remote payload did not match the expected contract (${field} must be a string when present)`);
|
|
7306
|
+
}
|
|
7307
|
+
return record3[field];
|
|
7308
|
+
}
|
|
7309
|
+
function normalizePin(entry) {
|
|
7310
|
+
if (!entry || typeof entry !== "object") {
|
|
7311
|
+
throw new Error("Remote pin payload did not match the expected contract (expected an object)");
|
|
7312
|
+
}
|
|
7313
|
+
const record3 = entry;
|
|
7314
|
+
const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
|
|
7315
|
+
if (!slug) {
|
|
7316
|
+
throw new Error("Remote pin payload did not match the expected contract (missing slug)");
|
|
7317
|
+
}
|
|
7318
|
+
let metadata;
|
|
7319
|
+
if (record3.metadata !== undefined) {
|
|
7320
|
+
if (!record3.metadata || typeof record3.metadata !== "object" || Array.isArray(record3.metadata)) {
|
|
7321
|
+
throw new Error("Remote pin payload did not match the expected contract (metadata must be a JSON object when present)");
|
|
7322
|
+
}
|
|
7323
|
+
metadata = record3.metadata;
|
|
7324
|
+
}
|
|
7325
|
+
const pinnedAt = requireOptionalString(record3, "pinnedAt");
|
|
7326
|
+
return {
|
|
7327
|
+
slug,
|
|
7328
|
+
...pinnedAt !== undefined ? { pinnedAt } : {},
|
|
7329
|
+
...metadata ? { metadata } : {}
|
|
7330
|
+
};
|
|
7331
|
+
}
|
|
7332
|
+
function normalizePinList(payload) {
|
|
7333
|
+
if (!Array.isArray(payload)) {
|
|
7334
|
+
throw new Error("Remote pins payload did not match the expected contract (expected an array of pins)");
|
|
7335
|
+
}
|
|
7336
|
+
return payload.map(normalizePin);
|
|
7337
|
+
}
|
|
7338
|
+
function normalizeSkillSummary(entry) {
|
|
7339
|
+
if (!entry || typeof entry !== "object") {
|
|
7340
|
+
throw new Error("Remote skill payload did not match the expected contract (expected an object)");
|
|
7341
|
+
}
|
|
7342
|
+
const record3 = entry;
|
|
7343
|
+
const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
|
|
7344
|
+
if (!slug) {
|
|
7345
|
+
throw new Error("Remote skill payload did not match the expected contract (missing slug)");
|
|
7346
|
+
}
|
|
7347
|
+
return {
|
|
7348
|
+
slug,
|
|
7349
|
+
...requireOptionalString(record3, "name") !== undefined ? { name: requireOptionalString(record3, "name") } : {},
|
|
7350
|
+
...requireOptionalString(record3, "version") !== undefined ? { version: requireOptionalString(record3, "version") } : {},
|
|
7351
|
+
...requireOptionalString(record3, "updatedAt") !== undefined ? { updatedAt: requireOptionalString(record3, "updatedAt") } : {}
|
|
7352
|
+
};
|
|
7353
|
+
}
|
|
7354
|
+
function normalizeSkillSummaryList(payload) {
|
|
7355
|
+
if (!Array.isArray(payload)) {
|
|
7356
|
+
throw new Error("Remote skills payload did not match the expected contract (expected an array of skills)");
|
|
7357
|
+
}
|
|
7358
|
+
return payload.map(normalizeSkillSummary);
|
|
7359
|
+
}
|
|
7360
|
+
async function responseBodyCarriesCode(response, codes) {
|
|
7361
|
+
try {
|
|
7362
|
+
const payload = await response.clone().json();
|
|
7363
|
+
if (!payload || typeof payload !== "object")
|
|
7364
|
+
return false;
|
|
7365
|
+
const code = payload.code;
|
|
7366
|
+
return typeof code === "string" && codes.includes(code);
|
|
7367
|
+
} catch {
|
|
7368
|
+
return false;
|
|
7369
|
+
}
|
|
7370
|
+
}
|
|
7371
|
+
function normalizeUpdatedSincePage(payload) {
|
|
7372
|
+
if (!payload || typeof payload !== "object") {
|
|
7373
|
+
throw new Error("Updated-since payload did not match the expected contract (expected an object)");
|
|
7374
|
+
}
|
|
7375
|
+
const record3 = payload;
|
|
7376
|
+
if (!Array.isArray(record3.skills)) {
|
|
7377
|
+
throw new Error("Updated-since payload did not match the expected contract (missing skills array)");
|
|
7378
|
+
}
|
|
7379
|
+
const skills = record3.skills.map(normalizeSkillSummary);
|
|
7380
|
+
const nextCursor = record3.nextCursor === undefined || record3.nextCursor === null ? null : record3.nextCursor;
|
|
7381
|
+
if (nextCursor !== null && typeof nextCursor !== "string") {
|
|
7382
|
+
throw new Error("Updated-since payload did not match the expected contract (nextCursor must be a string or absent)");
|
|
7383
|
+
}
|
|
7384
|
+
return { skills, nextCursor };
|
|
7166
7385
|
}
|
|
7167
7386
|
function createRemoteSkillsClient() {
|
|
7168
7387
|
const apiKey = getApiKey();
|
|
@@ -7170,8 +7389,42 @@ function createRemoteSkillsClient() {
|
|
|
7170
7389
|
return null;
|
|
7171
7390
|
return new RemoteSkillsClient(apiKey);
|
|
7172
7391
|
}
|
|
7392
|
+
function createRemoteSkillsClientReadOnly() {
|
|
7393
|
+
const apiKey = getApiKeyReadOnly();
|
|
7394
|
+
if (!apiKey)
|
|
7395
|
+
return null;
|
|
7396
|
+
const apiUrl = resolveApiUrl(loadConfigReadOnly(), process.env);
|
|
7397
|
+
if (!apiUrl)
|
|
7398
|
+
throw new MissingApiUrlError("the cloud group's sync verb (--dry-run)");
|
|
7399
|
+
return new RemoteSkillsClient(apiKey, apiUrl);
|
|
7400
|
+
}
|
|
7401
|
+
var RemoteRouteUnsupportedError, RemoteRequestError;
|
|
7173
7402
|
var init_remote_client = __esm(() => {
|
|
7174
7403
|
init_auth_store();
|
|
7404
|
+
init_api_url();
|
|
7405
|
+
init_config();
|
|
7406
|
+
RemoteRouteUnsupportedError = class RemoteRouteUnsupportedError extends Error {
|
|
7407
|
+
path;
|
|
7408
|
+
status;
|
|
7409
|
+
instance;
|
|
7410
|
+
constructor(path, status, instance) {
|
|
7411
|
+
super(`The configured Skills instance does not support ${path} (HTTP ${status}). ` + `The instance at ${instance} predates this client feature \u2014 upgrade the server, or ` + `use a client version that matches it.`);
|
|
7412
|
+
this.path = path;
|
|
7413
|
+
this.status = status;
|
|
7414
|
+
this.instance = instance;
|
|
7415
|
+
this.name = "RemoteRouteUnsupportedError";
|
|
7416
|
+
}
|
|
7417
|
+
};
|
|
7418
|
+
RemoteRequestError = class RemoteRequestError extends Error {
|
|
7419
|
+
path;
|
|
7420
|
+
status;
|
|
7421
|
+
constructor(path, status, statusText) {
|
|
7422
|
+
super(`Remote request to ${path} failed: HTTP ${status}${statusText ? ` ${statusText}` : ""}`);
|
|
7423
|
+
this.path = path;
|
|
7424
|
+
this.status = status;
|
|
7425
|
+
this.name = "RemoteRequestError";
|
|
7426
|
+
}
|
|
7427
|
+
};
|
|
7175
7428
|
});
|
|
7176
7429
|
|
|
7177
7430
|
// ../../node_modules/.bun/content-type@1.0.5/node_modules/content-type/index.js
|
|
@@ -12690,7 +12943,7 @@ class StdioServerTransport {
|
|
|
12690
12943
|
// package.json
|
|
12691
12944
|
var package_default = {
|
|
12692
12945
|
name: "@hasna/skills",
|
|
12693
|
-
version: "0.1.
|
|
12946
|
+
version: "0.1.64",
|
|
12694
12947
|
description: "Skills library for AI coding agents",
|
|
12695
12948
|
type: "module",
|
|
12696
12949
|
bin: {
|
|
@@ -12764,6 +13017,7 @@ var package_default = {
|
|
|
12764
13017
|
license: "Apache-2.0",
|
|
12765
13018
|
devDependencies: {
|
|
12766
13019
|
"@types/bun": "latest",
|
|
13020
|
+
"@types/node": "25.2.3",
|
|
12767
13021
|
"@types/react": "^18.2.0",
|
|
12768
13022
|
"bun-types": "1.3.14",
|
|
12769
13023
|
"react-devtools-core": "^7.0.1",
|
|
@@ -12772,7 +13026,7 @@ var package_default = {
|
|
|
12772
13026
|
dependencies: {
|
|
12773
13027
|
"@aws-sdk/client-ecs": "^3.1079.0",
|
|
12774
13028
|
"@aws-sdk/client-s3": "^3.1079.0",
|
|
12775
|
-
"@hasna/events": "0.1.
|
|
13029
|
+
"@hasna/events": "0.1.16",
|
|
12776
13030
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
12777
13031
|
chalk: "^5.3.0",
|
|
12778
13032
|
commander: "^12.1.0",
|
|
@@ -20800,7 +21054,7 @@ var DEVELOPMENT_TOOLS_SKILLS = [
|
|
|
20800
21054
|
{
|
|
20801
21055
|
name: "monitor",
|
|
20802
21056
|
displayName: "Monitor",
|
|
20803
|
-
description: "Operate the
|
|
21057
|
+
description: "Operate the monitor MCP for machine health, processes, cron jobs, and cleanup workflows",
|
|
20804
21058
|
category: "Development Tools",
|
|
20805
21059
|
tags: ["monitoring", "mcp", "processes", "operations"]
|
|
20806
21060
|
},
|
|
@@ -20846,6 +21100,14 @@ var DEVELOPMENT_TOOLS_SKILLS = [
|
|
|
20846
21100
|
description: "Validate configuration files for syntax and schema compliance",
|
|
20847
21101
|
category: "Development Tools",
|
|
20848
21102
|
tags: ["config", "validation", "schema", "linting"]
|
|
21103
|
+
},
|
|
21104
|
+
{
|
|
21105
|
+
name: "session-inject-monitor",
|
|
21106
|
+
displayName: "Session Inject Monitor",
|
|
21107
|
+
description: "Set up a declarative monitor that injects a prompt into a live coding-agent session when a watched source (conversations, email, todos, knowledge, command output) has new content",
|
|
21108
|
+
category: "Development Tools",
|
|
21109
|
+
tags: ["monitor", "session", "injection", "automation", "wake"],
|
|
21110
|
+
kind: "instruction"
|
|
20849
21111
|
}
|
|
20850
21112
|
];
|
|
20851
21113
|
|
|
@@ -21233,7 +21495,7 @@ var DESIGN_BRANDING_SKILLS = [
|
|
|
21233
21495
|
displayName: "Site Analyze",
|
|
21234
21496
|
description: "Analyze any website's design system \u2014 detects shadcn/ui, Tailwind, extracts colors, typography, and components via Playwright + Claude Vision.",
|
|
21235
21497
|
category: "Design & Branding",
|
|
21236
|
-
tags: ["design", "shadcn", "tailwind", "colors", "typography", "playwright", "analysis", "
|
|
21498
|
+
tags: ["design", "shadcn", "tailwind", "colors", "typography", "playwright", "analysis", "styles"]
|
|
21237
21499
|
}
|
|
21238
21500
|
];
|
|
21239
21501
|
|
|
@@ -22566,6 +22828,9 @@ function getPortableSkillsRoot(options = {}) {
|
|
|
22566
22828
|
if (options.rootDir)
|
|
22567
22829
|
return options.rootDir;
|
|
22568
22830
|
const appDir = options.homeDir ? join5(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
22831
|
+
const cache = join5(appDir, SKILLS_CACHE_DIRNAME);
|
|
22832
|
+
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
|
|
22833
|
+
return cache;
|
|
22569
22834
|
const installed = join5(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
22570
22835
|
migrateLegacySkillLayout(appDir, installed);
|
|
22571
22836
|
return installed;
|
|
@@ -23192,6 +23457,7 @@ import { fileURLToPath } from "url";
|
|
|
23192
23457
|
|
|
23193
23458
|
// src/lib/home-migration.ts
|
|
23194
23459
|
init_config();
|
|
23460
|
+
init_config();
|
|
23195
23461
|
|
|
23196
23462
|
// src/lib/utils.ts
|
|
23197
23463
|
function normalizeSkillName(name) {
|
|
@@ -25928,14 +26194,14 @@ function compactRunToolPayload(payload, detailHint) {
|
|
|
25928
26194
|
// src/lib/feedback.ts
|
|
25929
26195
|
init_config();
|
|
25930
26196
|
import { existsSync as existsSync13, mkdirSync as mkdirSync7 } from "fs";
|
|
25931
|
-
import { dirname as
|
|
26197
|
+
import { dirname as dirname6, join as join13 } from "path";
|
|
25932
26198
|
import { Database } from "bun:sqlite";
|
|
25933
26199
|
function getFeedbackDbPath() {
|
|
25934
26200
|
return join13(getDataDir(), "skills.db");
|
|
25935
26201
|
}
|
|
25936
26202
|
function getFeedbackDb() {
|
|
25937
26203
|
const dbPath = getFeedbackDbPath();
|
|
25938
|
-
const dir =
|
|
26204
|
+
const dir = dirname6(dbPath);
|
|
25939
26205
|
if (!existsSync13(dir))
|
|
25940
26206
|
mkdirSync7(dir, { recursive: true });
|
|
25941
26207
|
const db = new Database(dbPath);
|
|
@@ -26382,7 +26648,7 @@ import {
|
|
|
26382
26648
|
statSync as statSync8,
|
|
26383
26649
|
writeFileSync as writeFileSync8
|
|
26384
26650
|
} from "fs";
|
|
26385
|
-
import { dirname as
|
|
26651
|
+
import { dirname as dirname7, join as join15, normalize as normalize3, relative as relative3, sep as sep2 } from "path";
|
|
26386
26652
|
init_retired_settings();
|
|
26387
26653
|
var SKILLS_STORAGE_TABLES = [
|
|
26388
26654
|
"skills_sync_records",
|
|
@@ -26450,7 +26716,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
26450
26716
|
const s3BucketEnv = readStorageEnv(env, "s3Bucket");
|
|
26451
26717
|
const targetDir = options.targetDir ?? process.cwd();
|
|
26452
26718
|
return {
|
|
26453
|
-
package: "
|
|
26719
|
+
package: "skills",
|
|
26454
26720
|
tables: [...SKILLS_STORAGE_TABLES],
|
|
26455
26721
|
env: {
|
|
26456
26722
|
databaseUrl: SKILLS_NATIVE_STORAGE_ENV.databaseUrl,
|
|
@@ -26603,7 +26869,7 @@ function registerStorageTools(server) {
|
|
|
26603
26869
|
const snapshot = exportSkillsLocalSnapshot(targetDir, { includeFileContents: false });
|
|
26604
26870
|
const s3Plan = config2.s3Bucket ? planSkillsS3SnapshotUpload(snapshot, { prefix: config2.s3Prefix }) : [];
|
|
26605
26871
|
return mcpJson({
|
|
26606
|
-
package: "
|
|
26872
|
+
package: "skills",
|
|
26607
26873
|
noNetwork: true,
|
|
26608
26874
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
26609
26875
|
s3Configured: Boolean(config2.s3Bucket),
|