@hasna/skills 0.5.3 → 0.5.5
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 +72 -7
- package/bin/index.js +1429 -209
- package/bin/mcp.js +1545 -40
- package/bin/migrate.js +13 -4
- package/bin/server.js +81 -19
- package/bin/worker.js +37 -7
- package/dist/cli/commands/private-publications.d.ts +2 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +756 -24
- package/dist/lib/fleet-credentials.d.ts +6 -1
- package/dist/lib/home-adoption.d.ts +2 -7
- package/dist/lib/mcp-contracts.d.ts +1 -0
- package/dist/lib/private-publication-customer.d.ts +10 -0
- package/dist/lib/private-publication-recovery.d.ts +43 -0
- package/dist/lib/remote-account.d.ts +5 -0
- package/dist/lib/remote-auth.d.ts +3 -0
- package/dist/lib/remote-client.d.ts +9 -2
- package/dist/lib/remote-private-publications.d.ts +74 -0
- package/dist/lib/remote-quote-errors.d.ts +12 -0
- package/dist/mcp/private-publication-tools.d.ts +2 -0
- package/dist/sdk/execution/dispatchers/ecs.d.ts +25 -14
- package/dist/sdk/index.d.ts +4 -1
- package/dist/sdk/index.js +938 -164
- package/dist/server/types.d.ts +2 -0
- package/package.json +1 -1
package/bin/migrate.js
CHANGED
|
@@ -7,7 +7,7 @@ import { join as join6 } from "path";
|
|
|
7
7
|
// package.json
|
|
8
8
|
var package_default = {
|
|
9
9
|
name: "@hasna/skills",
|
|
10
|
-
version: "0.5.
|
|
10
|
+
version: "0.5.5",
|
|
11
11
|
description: "Skills library for AI coding agents",
|
|
12
12
|
type: "module",
|
|
13
13
|
bin: {
|
|
@@ -1246,10 +1246,16 @@ class SqliteSkillsStore {
|
|
|
1246
1246
|
const orgId = input.principal.orgId;
|
|
1247
1247
|
const now = nowIso();
|
|
1248
1248
|
return this.db.transaction(() => {
|
|
1249
|
-
const previous = this.get("SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at FROM skills_registry WHERE org_id = ? AND slug = ?", [orgId, input.slug]);
|
|
1249
|
+
const previous = this.get("SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at, source FROM skills_registry WHERE org_id = ? AND slug = ?", [orgId, input.slug]);
|
|
1250
1250
|
const previousSha = typeof previous?.bundle_sha256 === "string" ? previous.bundle_sha256 : null;
|
|
1251
1251
|
const previousRevisionId = typeof previous?.revision_id === "string" && previous.revision_id ? previous.revision_id : null;
|
|
1252
1252
|
const tombstoned = previous?.tombstoned_at != null;
|
|
1253
|
+
if (input.seedBundledOnly && input.expectedRevisionId && !previous) {
|
|
1254
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, null);
|
|
1255
|
+
}
|
|
1256
|
+
if (input.seedBundledOnly && previous && (tombstoned || previous.source !== "bundled")) {
|
|
1257
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
|
|
1258
|
+
}
|
|
1253
1259
|
const carriedSkillMd = typeof input.skillMd === "string" ? input.skillMd : typeof previous?.skill_md === "string" ? previous.skill_md : null;
|
|
1254
1260
|
if (previous && !tombstoned && input.expectedRevisionId !== previousRevisionId) {
|
|
1255
1261
|
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
|
|
@@ -1323,8 +1329,9 @@ class SqliteSkillsStore {
|
|
|
1323
1329
|
tombstoned_at = NULL,
|
|
1324
1330
|
tombstone_purge_after = NULL,
|
|
1325
1331
|
updated_at = excluded.updated_at
|
|
1326
|
-
WHERE skills_registry.tombstoned_at IS NOT NULL
|
|
1327
|
-
|
|
1332
|
+
WHERE (skills_registry.tombstoned_at IS NOT NULL OR skills_registry.revision_id = ?)
|
|
1333
|
+
AND (? = 0 OR (skills_registry.tombstoned_at IS NULL AND skills_registry.source = 'bundled'
|
|
1334
|
+
AND skills_registry.revision_id = ?))
|
|
1328
1335
|
RETURNING *`, [
|
|
1329
1336
|
orgId,
|
|
1330
1337
|
input.slug,
|
|
@@ -1342,6 +1349,8 @@ class SqliteSkillsStore {
|
|
|
1342
1349
|
revisionId,
|
|
1343
1350
|
now,
|
|
1344
1351
|
now,
|
|
1352
|
+
input.expectedRevisionId ?? NO_REVISION_SENTINEL,
|
|
1353
|
+
input.seedBundledOnly ? 1 : 0,
|
|
1345
1354
|
input.expectedRevisionId ?? NO_REVISION_SENTINEL
|
|
1346
1355
|
]);
|
|
1347
1356
|
if (!row) {
|
package/bin/server.js
CHANGED
|
@@ -23100,7 +23100,7 @@ var init_dist_es9 = __esm(() => {
|
|
|
23100
23100
|
// package.json
|
|
23101
23101
|
var package_default = {
|
|
23102
23102
|
name: "@hasna/skills",
|
|
23103
|
-
version: "0.5.
|
|
23103
|
+
version: "0.5.5",
|
|
23104
23104
|
description: "Skills library for AI coding agents",
|
|
23105
23105
|
type: "module",
|
|
23106
23106
|
bin: {
|
|
@@ -34472,10 +34472,16 @@ class SqliteSkillsStore {
|
|
|
34472
34472
|
const orgId = input.principal.orgId;
|
|
34473
34473
|
const now = nowIso();
|
|
34474
34474
|
return this.db.transaction(() => {
|
|
34475
|
-
const previous = this.get("SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at FROM skills_registry WHERE org_id = ? AND slug = ?", [orgId, input.slug]);
|
|
34475
|
+
const previous = this.get("SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at, source FROM skills_registry WHERE org_id = ? AND slug = ?", [orgId, input.slug]);
|
|
34476
34476
|
const previousSha = typeof previous?.bundle_sha256 === "string" ? previous.bundle_sha256 : null;
|
|
34477
34477
|
const previousRevisionId = typeof previous?.revision_id === "string" && previous.revision_id ? previous.revision_id : null;
|
|
34478
34478
|
const tombstoned = previous?.tombstoned_at != null;
|
|
34479
|
+
if (input.seedBundledOnly && input.expectedRevisionId && !previous) {
|
|
34480
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, null);
|
|
34481
|
+
}
|
|
34482
|
+
if (input.seedBundledOnly && previous && (tombstoned || previous.source !== "bundled")) {
|
|
34483
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
|
|
34484
|
+
}
|
|
34479
34485
|
const carriedSkillMd = typeof input.skillMd === "string" ? input.skillMd : typeof previous?.skill_md === "string" ? previous.skill_md : null;
|
|
34480
34486
|
if (previous && !tombstoned && input.expectedRevisionId !== previousRevisionId) {
|
|
34481
34487
|
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
|
|
@@ -34549,8 +34555,9 @@ class SqliteSkillsStore {
|
|
|
34549
34555
|
tombstoned_at = NULL,
|
|
34550
34556
|
tombstone_purge_after = NULL,
|
|
34551
34557
|
updated_at = excluded.updated_at
|
|
34552
|
-
WHERE skills_registry.tombstoned_at IS NOT NULL
|
|
34553
|
-
|
|
34558
|
+
WHERE (skills_registry.tombstoned_at IS NOT NULL OR skills_registry.revision_id = ?)
|
|
34559
|
+
AND (? = 0 OR (skills_registry.tombstoned_at IS NULL AND skills_registry.source = 'bundled'
|
|
34560
|
+
AND skills_registry.revision_id = ?))
|
|
34554
34561
|
RETURNING *`, [
|
|
34555
34562
|
orgId,
|
|
34556
34563
|
input.slug,
|
|
@@ -34568,6 +34575,8 @@ class SqliteSkillsStore {
|
|
|
34568
34575
|
revisionId,
|
|
34569
34576
|
now,
|
|
34570
34577
|
now,
|
|
34578
|
+
input.expectedRevisionId ?? NO_REVISION_SENTINEL,
|
|
34579
|
+
input.seedBundledOnly ? 1 : 0,
|
|
34571
34580
|
input.expectedRevisionId ?? NO_REVISION_SENTINEL
|
|
34572
34581
|
]);
|
|
34573
34582
|
if (!row) {
|
|
@@ -36875,6 +36884,12 @@ async function storePublishedSkill(store, artifactStorage, principal, parsed, ex
|
|
|
36875
36884
|
principal,
|
|
36876
36885
|
...expectedRevisionId ? { expectedRevisionId } : {}
|
|
36877
36886
|
};
|
|
36887
|
+
if (input.seedBundledOnly && expectedRevisionId && !current) {
|
|
36888
|
+
throw new SkillRevisionConflictError(input.slug, expectedRevisionId, null);
|
|
36889
|
+
}
|
|
36890
|
+
if (input.seedBundledOnly && current && (current.tombstonedAt || current.source !== "bundled")) {
|
|
36891
|
+
throw new SkillRevisionConflictError(input.slug, expectedRevisionId, current.revisionId);
|
|
36892
|
+
}
|
|
36878
36893
|
if (current && !current.tombstonedAt && expectedRevisionId !== current.revisionId) {
|
|
36879
36894
|
throw new SkillRevisionConflictError(input.slug, expectedRevisionId, current.revisionId);
|
|
36880
36895
|
}
|
|
@@ -37124,6 +37139,15 @@ async function seedBundledCorpus(options) {
|
|
|
37124
37139
|
result.skipped.push(slug);
|
|
37125
37140
|
continue;
|
|
37126
37141
|
}
|
|
37142
|
+
const current = await options.store.getSkill(options.principal, slug);
|
|
37143
|
+
if (current) {
|
|
37144
|
+
const previousVersion = current.version ? await options.store.getSkillVersion(options.principal, slug, current.version) : null;
|
|
37145
|
+
const provenance = previousVersion?.manifest.provenance;
|
|
37146
|
+
if (current.tombstonedAt || current.source !== "bundled" || provenance?.seededFrom !== "bundled-corpus" || provenance.seededRevisionId !== current.revisionId) {
|
|
37147
|
+
result.skipped.push(slug);
|
|
37148
|
+
continue;
|
|
37149
|
+
}
|
|
37150
|
+
}
|
|
37127
37151
|
const dir = getSkillPath(slug);
|
|
37128
37152
|
if (!existsSync11(dir)) {
|
|
37129
37153
|
result.skipped.push(slug);
|
|
@@ -37133,32 +37157,40 @@ async function seedBundledCorpus(options) {
|
|
|
37133
37157
|
const packed = packSkillBundle(dir, { maxUnpackedBytes: 50000000 });
|
|
37134
37158
|
const skillMdPath = join14(dir, "SKILL.md");
|
|
37135
37159
|
const skillMd = existsSync11(skillMdPath) ? readFileSync11(skillMdPath, "utf-8") : undefined;
|
|
37136
|
-
const
|
|
37160
|
+
const content = {
|
|
37161
|
+
slug,
|
|
37162
|
+
displayName: manifest.displayName ?? skill.displayName ?? slug,
|
|
37163
|
+
description: manifest.description ?? skill.description ?? slug,
|
|
37164
|
+
category: manifest.category ?? skill.category ?? "Development Tools",
|
|
37165
|
+
tags: manifest.tags ?? skill.tags ?? [],
|
|
37166
|
+
source: "bundled",
|
|
37167
|
+
kind: manifest.kind ?? "instruction",
|
|
37168
|
+
version: version2,
|
|
37169
|
+
...skillMd ? { skillMd } : {},
|
|
37170
|
+
bundleSha256: packed.sha256,
|
|
37171
|
+
bundleByteSize: packed.bytes.byteLength
|
|
37172
|
+
};
|
|
37137
37173
|
const { record } = await storePublishedSkill(options.store, options.artifactStorage, options.principal, {
|
|
37138
37174
|
input: {
|
|
37139
|
-
|
|
37140
|
-
|
|
37141
|
-
description: manifest.description ?? skill.description ?? slug,
|
|
37142
|
-
category: manifest.category ?? skill.category ?? "Development Tools",
|
|
37143
|
-
tags: manifest.tags ?? skill.tags ?? [],
|
|
37144
|
-
source: "bundled",
|
|
37145
|
-
kind: manifest.kind ?? "instruction",
|
|
37146
|
-
version: version2,
|
|
37147
|
-
...skillMd ? { skillMd } : {},
|
|
37175
|
+
...content,
|
|
37176
|
+
seedBundledOnly: true,
|
|
37148
37177
|
bundle: { sha256: packed.sha256, byteSize: packed.bytes.byteLength, contentType: "application/gzip", storageKind: "db" },
|
|
37149
37178
|
versionManifest: {
|
|
37150
37179
|
files: packed.paths,
|
|
37151
37180
|
fileCount: packed.fileCount,
|
|
37152
37181
|
unpackedByteSize: packed.unpackedByteSize,
|
|
37153
37182
|
bundleSha256: packed.sha256,
|
|
37154
|
-
provenance: { seededFrom: "bundled-corpus", packageVersion: package_default.version }
|
|
37183
|
+
provenance: { seededFrom: "bundled-corpus", packageVersion: package_default.version, seededRevisionId: revisionIdOfRecord(content) }
|
|
37155
37184
|
}
|
|
37156
37185
|
},
|
|
37157
37186
|
bundleBytes: packed.bytes
|
|
37158
37187
|
}, current?.revisionId);
|
|
37159
37188
|
result.seeded.push(`${record.slug}@${version2}`);
|
|
37160
37189
|
} catch (error) {
|
|
37161
|
-
|
|
37190
|
+
if (error instanceof SkillRevisionConflictError)
|
|
37191
|
+
result.skipped.push(slug);
|
|
37192
|
+
else
|
|
37193
|
+
result.failed.push({ slug, error: error.message });
|
|
37162
37194
|
}
|
|
37163
37195
|
}
|
|
37164
37196
|
log(`skills: bundled corpus seed v${version2}: ${result.seeded.length} seeded, ${result.skipped.length} skipped, ${result.failed.length} failed`);
|
|
@@ -37368,6 +37400,12 @@ class MemorySkillsStore {
|
|
|
37368
37400
|
const key = skillKey(input.principal.orgId, input.slug);
|
|
37369
37401
|
const now = nowIso();
|
|
37370
37402
|
const previous = this.skills.get(key);
|
|
37403
|
+
if (input.seedBundledOnly && input.expectedRevisionId && !previous) {
|
|
37404
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, null);
|
|
37405
|
+
}
|
|
37406
|
+
if (input.seedBundledOnly && previous && (previous.tombstonedAt || previous.source !== "bundled")) {
|
|
37407
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previous.revisionId);
|
|
37408
|
+
}
|
|
37371
37409
|
if (previous && !previous.tombstonedAt && input.expectedRevisionId !== previous.revisionId) {
|
|
37372
37410
|
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previous.revisionId);
|
|
37373
37411
|
}
|
|
@@ -37821,13 +37859,19 @@ class PostgresSkillsStore {
|
|
|
37821
37859
|
const orgId = input.principal.orgId;
|
|
37822
37860
|
return await this.sql.begin(async (tx) => {
|
|
37823
37861
|
const previousRows = await tx`
|
|
37824
|
-
SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at
|
|
37862
|
+
SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at, source
|
|
37825
37863
|
FROM skills_registry WHERE org_id = ${orgId} AND slug = ${input.slug} LIMIT 1
|
|
37826
37864
|
`;
|
|
37827
37865
|
const previous = previousRows[0];
|
|
37828
37866
|
const previousSha = typeof previous?.bundle_sha256 === "string" ? String(previous.bundle_sha256) : null;
|
|
37829
37867
|
const previousRevisionId = typeof previous?.revision_id === "string" && previous.revision_id ? String(previous.revision_id) : null;
|
|
37830
37868
|
const tombstoned = previous?.tombstoned_at != null;
|
|
37869
|
+
if (input.seedBundledOnly && input.expectedRevisionId && !previous) {
|
|
37870
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, null);
|
|
37871
|
+
}
|
|
37872
|
+
if (input.seedBundledOnly && previous && (tombstoned || previous.source !== "bundled")) {
|
|
37873
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
|
|
37874
|
+
}
|
|
37831
37875
|
const carriedSkillMd = typeof input.skillMd === "string" ? input.skillMd : typeof previous?.skill_md === "string" ? String(previous.skill_md) : null;
|
|
37832
37876
|
if (previous && !tombstoned && input.expectedRevisionId !== previousRevisionId) {
|
|
37833
37877
|
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
|
|
@@ -37868,6 +37912,12 @@ class PostgresSkillsStore {
|
|
|
37868
37912
|
body_blob = EXCLUDED.body_blob
|
|
37869
37913
|
`;
|
|
37870
37914
|
}
|
|
37915
|
+
if (input.seedBundledOnly) {
|
|
37916
|
+
const seedRows = await tx`SELECT revision_id FROM skills_registry WHERE org_id = ${orgId} AND slug = ${input.slug} FOR UPDATE`;
|
|
37917
|
+
if (input.expectedRevisionId && !seedRows[0]) {
|
|
37918
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, null);
|
|
37919
|
+
}
|
|
37920
|
+
}
|
|
37871
37921
|
const rows = await tx`
|
|
37872
37922
|
INSERT INTO skills_registry (org_id, slug, display_name, description, category, tags_json, source, kind, version, skill_md,
|
|
37873
37923
|
bundle_sha256, bundle_byte_size, published_by_user_id, revision_id, revision_number, updated_at)
|
|
@@ -37896,8 +37946,11 @@ class PostgresSkillsStore {
|
|
|
37896
37946
|
tombstoned_at = NULL,
|
|
37897
37947
|
tombstone_purge_after = NULL,
|
|
37898
37948
|
updated_at = EXCLUDED.updated_at
|
|
37899
|
-
WHERE skills_registry.tombstoned_at IS NOT NULL
|
|
37900
|
-
OR skills_registry.revision_id = ${input.expectedRevisionId ?? NO_REVISION_SENTINEL2}
|
|
37949
|
+
WHERE (skills_registry.tombstoned_at IS NOT NULL
|
|
37950
|
+
OR skills_registry.revision_id = ${input.expectedRevisionId ?? NO_REVISION_SENTINEL2})
|
|
37951
|
+
AND (NOT ${Boolean(input.seedBundledOnly)} OR
|
|
37952
|
+
(skills_registry.tombstoned_at IS NULL AND skills_registry.source = 'bundled'
|
|
37953
|
+
AND skills_registry.revision_id = ${input.expectedRevisionId ?? NO_REVISION_SENTINEL2}))
|
|
37901
37954
|
RETURNING *
|
|
37902
37955
|
`;
|
|
37903
37956
|
if (!rows[0]) {
|
|
@@ -38312,6 +38365,15 @@ async function createSkillsFetchHandler(options = {}) {
|
|
|
38312
38365
|
}
|
|
38313
38366
|
return async function fetch(request) {
|
|
38314
38367
|
const url = new URL(request.url);
|
|
38368
|
+
const versionedAliases = {
|
|
38369
|
+
"/v1/health": "/health",
|
|
38370
|
+
"/v1/auth/whoami": "/api/auth/whoami"
|
|
38371
|
+
};
|
|
38372
|
+
const alias = versionedAliases[url.pathname] ?? (url.pathname === "/v1" || url.pathname.startsWith("/v1/") ? `/api${url.pathname}` : undefined);
|
|
38373
|
+
if (alias) {
|
|
38374
|
+
url.pathname = alias;
|
|
38375
|
+
request = new Request(url, request);
|
|
38376
|
+
}
|
|
38315
38377
|
const segments = pathSegments(url.pathname);
|
|
38316
38378
|
try {
|
|
38317
38379
|
if (request.method === "GET" && url.pathname === "/health") {
|
package/bin/worker.js
CHANGED
|
@@ -23103,7 +23103,7 @@ import { randomUUID as randomUUID4 } from "crypto";
|
|
|
23103
23103
|
// package.json
|
|
23104
23104
|
var package_default = {
|
|
23105
23105
|
name: "@hasna/skills",
|
|
23106
|
-
version: "0.5.
|
|
23106
|
+
version: "0.5.5",
|
|
23107
23107
|
description: "Skills library for AI coding agents",
|
|
23108
23108
|
type: "module",
|
|
23109
23109
|
bin: {
|
|
@@ -34128,10 +34128,16 @@ class SqliteSkillsStore {
|
|
|
34128
34128
|
const orgId = input.principal.orgId;
|
|
34129
34129
|
const now = nowIso();
|
|
34130
34130
|
return this.db.transaction(() => {
|
|
34131
|
-
const previous = this.get("SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at FROM skills_registry WHERE org_id = ? AND slug = ?", [orgId, input.slug]);
|
|
34131
|
+
const previous = this.get("SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at, source FROM skills_registry WHERE org_id = ? AND slug = ?", [orgId, input.slug]);
|
|
34132
34132
|
const previousSha = typeof previous?.bundle_sha256 === "string" ? previous.bundle_sha256 : null;
|
|
34133
34133
|
const previousRevisionId = typeof previous?.revision_id === "string" && previous.revision_id ? previous.revision_id : null;
|
|
34134
34134
|
const tombstoned = previous?.tombstoned_at != null;
|
|
34135
|
+
if (input.seedBundledOnly && input.expectedRevisionId && !previous) {
|
|
34136
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, null);
|
|
34137
|
+
}
|
|
34138
|
+
if (input.seedBundledOnly && previous && (tombstoned || previous.source !== "bundled")) {
|
|
34139
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
|
|
34140
|
+
}
|
|
34135
34141
|
const carriedSkillMd = typeof input.skillMd === "string" ? input.skillMd : typeof previous?.skill_md === "string" ? previous.skill_md : null;
|
|
34136
34142
|
if (previous && !tombstoned && input.expectedRevisionId !== previousRevisionId) {
|
|
34137
34143
|
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
|
|
@@ -34205,8 +34211,9 @@ class SqliteSkillsStore {
|
|
|
34205
34211
|
tombstoned_at = NULL,
|
|
34206
34212
|
tombstone_purge_after = NULL,
|
|
34207
34213
|
updated_at = excluded.updated_at
|
|
34208
|
-
WHERE skills_registry.tombstoned_at IS NOT NULL
|
|
34209
|
-
|
|
34214
|
+
WHERE (skills_registry.tombstoned_at IS NOT NULL OR skills_registry.revision_id = ?)
|
|
34215
|
+
AND (? = 0 OR (skills_registry.tombstoned_at IS NULL AND skills_registry.source = 'bundled'
|
|
34216
|
+
AND skills_registry.revision_id = ?))
|
|
34210
34217
|
RETURNING *`, [
|
|
34211
34218
|
orgId,
|
|
34212
34219
|
input.slug,
|
|
@@ -34224,6 +34231,8 @@ class SqliteSkillsStore {
|
|
|
34224
34231
|
revisionId,
|
|
34225
34232
|
now,
|
|
34226
34233
|
now,
|
|
34234
|
+
input.expectedRevisionId ?? NO_REVISION_SENTINEL,
|
|
34235
|
+
input.seedBundledOnly ? 1 : 0,
|
|
34227
34236
|
input.expectedRevisionId ?? NO_REVISION_SENTINEL
|
|
34228
34237
|
]);
|
|
34229
34238
|
if (!row) {
|
|
@@ -35515,6 +35524,12 @@ class MemorySkillsStore {
|
|
|
35515
35524
|
const key = skillKey(input.principal.orgId, input.slug);
|
|
35516
35525
|
const now = nowIso();
|
|
35517
35526
|
const previous = this.skills.get(key);
|
|
35527
|
+
if (input.seedBundledOnly && input.expectedRevisionId && !previous) {
|
|
35528
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, null);
|
|
35529
|
+
}
|
|
35530
|
+
if (input.seedBundledOnly && previous && (previous.tombstonedAt || previous.source !== "bundled")) {
|
|
35531
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previous.revisionId);
|
|
35532
|
+
}
|
|
35518
35533
|
if (previous && !previous.tombstonedAt && input.expectedRevisionId !== previous.revisionId) {
|
|
35519
35534
|
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previous.revisionId);
|
|
35520
35535
|
}
|
|
@@ -35968,13 +35983,19 @@ class PostgresSkillsStore {
|
|
|
35968
35983
|
const orgId = input.principal.orgId;
|
|
35969
35984
|
return await this.sql.begin(async (tx) => {
|
|
35970
35985
|
const previousRows = await tx`
|
|
35971
|
-
SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at
|
|
35986
|
+
SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at, source
|
|
35972
35987
|
FROM skills_registry WHERE org_id = ${orgId} AND slug = ${input.slug} LIMIT 1
|
|
35973
35988
|
`;
|
|
35974
35989
|
const previous = previousRows[0];
|
|
35975
35990
|
const previousSha = typeof previous?.bundle_sha256 === "string" ? String(previous.bundle_sha256) : null;
|
|
35976
35991
|
const previousRevisionId = typeof previous?.revision_id === "string" && previous.revision_id ? String(previous.revision_id) : null;
|
|
35977
35992
|
const tombstoned = previous?.tombstoned_at != null;
|
|
35993
|
+
if (input.seedBundledOnly && input.expectedRevisionId && !previous) {
|
|
35994
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, null);
|
|
35995
|
+
}
|
|
35996
|
+
if (input.seedBundledOnly && previous && (tombstoned || previous.source !== "bundled")) {
|
|
35997
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
|
|
35998
|
+
}
|
|
35978
35999
|
const carriedSkillMd = typeof input.skillMd === "string" ? input.skillMd : typeof previous?.skill_md === "string" ? String(previous.skill_md) : null;
|
|
35979
36000
|
if (previous && !tombstoned && input.expectedRevisionId !== previousRevisionId) {
|
|
35980
36001
|
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
|
|
@@ -36015,6 +36036,12 @@ class PostgresSkillsStore {
|
|
|
36015
36036
|
body_blob = EXCLUDED.body_blob
|
|
36016
36037
|
`;
|
|
36017
36038
|
}
|
|
36039
|
+
if (input.seedBundledOnly) {
|
|
36040
|
+
const seedRows = await tx`SELECT revision_id FROM skills_registry WHERE org_id = ${orgId} AND slug = ${input.slug} FOR UPDATE`;
|
|
36041
|
+
if (input.expectedRevisionId && !seedRows[0]) {
|
|
36042
|
+
throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, null);
|
|
36043
|
+
}
|
|
36044
|
+
}
|
|
36018
36045
|
const rows = await tx`
|
|
36019
36046
|
INSERT INTO skills_registry (org_id, slug, display_name, description, category, tags_json, source, kind, version, skill_md,
|
|
36020
36047
|
bundle_sha256, bundle_byte_size, published_by_user_id, revision_id, revision_number, updated_at)
|
|
@@ -36043,8 +36070,11 @@ class PostgresSkillsStore {
|
|
|
36043
36070
|
tombstoned_at = NULL,
|
|
36044
36071
|
tombstone_purge_after = NULL,
|
|
36045
36072
|
updated_at = EXCLUDED.updated_at
|
|
36046
|
-
WHERE skills_registry.tombstoned_at IS NOT NULL
|
|
36047
|
-
OR skills_registry.revision_id = ${input.expectedRevisionId ?? NO_REVISION_SENTINEL2}
|
|
36073
|
+
WHERE (skills_registry.tombstoned_at IS NOT NULL
|
|
36074
|
+
OR skills_registry.revision_id = ${input.expectedRevisionId ?? NO_REVISION_SENTINEL2})
|
|
36075
|
+
AND (NOT ${Boolean(input.seedBundledOnly)} OR
|
|
36076
|
+
(skills_registry.tombstoned_at IS NULL AND skills_registry.source = 'bundled'
|
|
36077
|
+
AND skills_registry.revision_id = ${input.expectedRevisionId ?? NO_REVISION_SENTINEL2}))
|
|
36048
36078
|
RETURNING *
|
|
36049
36079
|
`;
|
|
36050
36080
|
if (!rows[0]) {
|
package/dist/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export { ARTICLE_GENERATION_SLUG, validateBlogArticleRunOptions, type BlogArticl
|
|
|
18
18
|
export { getCompactSkillDiscovery, getPublicSkillDiscovery, publicDiscoveryDependencies, publicDiscoveryDocumentation, publicDiscoveryEnvVars, sanitizePublicDiscoveryText, type CompactSkillDiscovery, type PublicSkillDiscovery, } from "./lib/discovery.js";
|
|
19
19
|
export { TOOL_PRIMITIVE_SCHEMA_VERSION, TOOL_PRIMITIVES, createSkillToolDependencies, getSkillToolDependencies, getToolPrimitive, isGatewayBackedSkill, listToolPrimitives, validateToolPrimitiveCoverage, type SkillToolDependencies, type SkillToolDependency, type ToolPrimitive, type ToolPrimitiveCoverageIssue, type ToolPrimitiveCoverageResult, type ToolPrimitiveRuntime, type ToolPrimitiveSummary, } from "./lib/tool-primitives.js";
|
|
20
20
|
export { MissingSkillsFleetError, SkillsFleetCredentialError, SKILLS_API_KEY_ENV, SKILLS_API_KEY_ENV_KEYS, SKILLS_API_URL_ENV, SKILLS_API_URL_ENV_KEYS, SKILLS_APP, SKILLS_LOCAL_OPT_IN_ENV_KEYS, configuredSkillsApiUrl, isSkillsLocalOptIn, noticeLocalSkillsMode, normalizeSkillsApiOrigin, requireSkillsApiKey, requireSkillsApiOrigin, requireSkillsFleet, resolveSkillsApiKey, resolveSkillsApiOrigin, resolveSkillsFleet, selectsSkillsLocalMode, skillsCredentialFilePath, skillsCredentialFiles, skillsCredentialOrReason, type HostedSkillsFleet, type LocalSkillsFleet, type SkillsFleet, type SkillsFleetErrorCode, type SkillsFleetOptions, } from "./lib/fleet-credentials.js";
|
|
21
|
-
export { RemoteSkillsClient, createRemoteSkillsClient, RemoteRouteUnsupportedError, RemoteRequestError, RemoteWorkspaceMemberError, RemoteCapabilityUnavailableError, type RemotePin, type RemoteSkillSummary, type UpdatedSincePage, } from "./lib/remote-client.js";
|
|
21
|
+
export { RemoteSkillsClient, createRemoteSkillsClient, RemoteRouteUnsupportedError, RemoteRequestError, RemoteQuoteUnavailableError, type RemoteQuoteUnavailableCode, RemoteWorkspaceMemberError, RemoteCapabilityUnavailableError, type RemotePin, type RemoteSkillSummary, type UpdatedSincePage, } from "./lib/remote-client.js";
|
|
22
22
|
export { REMOTE_SKILL_RUN_CONTRACT_VERSION, normalizeRemoteSkillRunContract, type RemoteSkillRunContract, } from "./lib/remote-run-contract.js";
|
|
23
23
|
export { addSchedule, listSchedules, removeSchedule, setScheduleEnabled, getDueSchedules, recordScheduleRun, validateCron, getNextRun, type SkillSchedule, } from "./lib/scheduler.js";
|
|
24
24
|
export { parseSkillFrontmatter, validateRegistryConsistency, validateSkillDirectory, type RegistryConsistencyResult, type SkillFrontmatter, type SkillValidationMessage, type SkillValidationResult, } from "./lib/skill-validation.js";
|
|
@@ -52,3 +52,5 @@ export { WorkspaceLeaveInputError, RemoteWorkspaceLeaveError, RemoteWorkspaceLea
|
|
|
52
52
|
export type { RemoteWorkspaceInvitation, RemoteWorkspaceInvitationsPage, RemoteWorkspaceInvitationResult, RemoteWorkspaceInvitationAcceptance, ListRemoteWorkspaceInvitations, IssueRemoteWorkspaceInvitation, ResendRemoteWorkspaceInvitation, RevokeRemoteWorkspaceInvitation, AcceptRemoteWorkspaceInvitation, RemoteWorkspaceInvitationErrorCode } from "./lib/remote-invitations.js";
|
|
53
53
|
export { WorkspaceInvitationInputError, RemoteWorkspaceInvitationError, RemoteWorkspaceInvitationUnconfirmedError, RemoteWorkspaceInvitationReadError } from "./lib/remote-invitations.js";
|
|
54
54
|
export { InvitationEmailInputError, RemoteInvitationEmailError, RemoteInvitationEmailUnconfirmedError, type RequestInvitationEmailChallenge, type AcceptInvitationEmailChallenge, type RemoteInvitationEmailChallenge, type RemoteInvitationEmailAcceptance, type RemoteInvitationEmailErrorCode } from "./lib/remote-invitation-recovery.js";
|
|
55
|
+
export { RemotePrivatePublicationsClient, PrivatePublicationError, PRIVATE_PUBLICATION_MAX_BYTES, type PrivatePublicationDeclaration, type PrivatePublicationView, type PrivatePublicationState, type PrivatePublishingCapability } from "./lib/remote-private-publications.js";
|
|
56
|
+
export { preparePrivatePublication, readPrivatePublicationRecovery, continuePrivatePublication, inspectPrivatePublication, type PrivatePublicationRecovery, type PrivatePublicationResult } from "./lib/private-publication-recovery.js";
|