@hasna/skills 0.8.12 → 0.9.2
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 +21 -5
- package/bin/index.js +271 -19
- package/bin/mcp.js +248 -154
- package/bin/migrate.js +100 -10
- package/bin/server.js +596 -51
- package/bin/worker.js +283 -20
- package/dist/cli/commands/registry.d.ts +1 -0
- package/dist/index.js +122 -13
- package/dist/lib/agent-integration.d.ts +26 -0
- package/dist/lib/cloud-executions.d.ts +20 -0
- package/dist/lib/registry-types.d.ts +3 -0
- package/dist/lib/remote-client.d.ts +11 -0
- package/dist/lib/revision.d.ts +3 -0
- package/dist/sdk/execution/admission.d.ts +2 -1
- package/dist/sdk/execution/types.d.ts +9 -0
- package/dist/sdk/index.d.ts +1 -0
- package/dist/sdk/index.js +1301 -502
- package/dist/server/runtime-policy.d.ts +4 -2
- package/dist/server/runtime-pure-contract.d.ts +51 -0
- package/dist/server/runtime-store.d.ts +4 -0
- package/dist/server/runtime-worker.d.ts +2 -1
- package/dist/server/selection-store.d.ts +9 -1
- package/dist/server/skills-api.d.ts +2 -1
- package/dist/server/sqlite-store.d.ts +4 -1
- package/dist/server/store.d.ts +6 -1
- package/dist/server/types.d.ts +27 -0
- package/migrations/postgres/0010_skill_archive_lifecycle.sql +5 -0
- package/migrations/sqlite/0010_skill_archive_lifecycle.sql +5 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8323,6 +8323,7 @@ function readManifest(skillPath, fallbackName, normalizeName) {
|
|
|
8323
8323
|
const version = readDeclaredSkillVersion(skillPath) ?? PORTABLE_SKILL_DEFAULT_VERSION;
|
|
8324
8324
|
const kind = parseSkillKind(stringField(jsonManifest, "kind") ?? frontmatter?.kind);
|
|
8325
8325
|
const commands = parseManifestCommands(jsonManifest) ?? (kind === "instruction" ? [] : inferPackageCommands(pkg, name)) ?? [];
|
|
8326
|
+
const runtime = parseManifestRuntime(jsonManifest) ?? inferRuntimeFromCommands(commands);
|
|
8326
8327
|
return {
|
|
8327
8328
|
$schema: stringField(jsonManifest, "$schema") ?? PORTABLE_SKILL_SCHEMA,
|
|
8328
8329
|
standard: stringField(jsonManifest, "standard") ?? PORTABLE_SKILL_STANDARD,
|
|
@@ -8335,7 +8336,7 @@ function readManifest(skillPath, fallbackName, normalizeName) {
|
|
|
8335
8336
|
...kind ? { kind } : {},
|
|
8336
8337
|
inputs: kind === "instruction" ? parseManifestInputs(jsonManifest) ?? [] : parseManifestInputs(jsonManifest) ?? DEFAULT_INPUTS,
|
|
8337
8338
|
commands,
|
|
8338
|
-
...
|
|
8339
|
+
...runtime ? { runtime } : {},
|
|
8339
8340
|
...parseManifestProvenance(jsonManifest) ? { provenance: parseManifestProvenance(jsonManifest) } : {}
|
|
8340
8341
|
};
|
|
8341
8342
|
}
|
|
@@ -8854,6 +8855,12 @@ function inferPackageCommands(pkg, fallbackName) {
|
|
|
8854
8855
|
}
|
|
8855
8856
|
return;
|
|
8856
8857
|
}
|
|
8858
|
+
function inferRuntimeFromCommands(commands) {
|
|
8859
|
+
const entrypoint = commands.find((command) => command.entry)?.entry;
|
|
8860
|
+
if (!entrypoint || !entrypoint.toLowerCase().endsWith(".py"))
|
|
8861
|
+
return;
|
|
8862
|
+
return { ...defaultRuntimeContract(entrypoint), runtime: "python3" };
|
|
8863
|
+
}
|
|
8857
8864
|
function readJsonObject(path) {
|
|
8858
8865
|
const parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
8859
8866
|
if (!isRecord2(parsed))
|
|
@@ -11441,7 +11448,7 @@ import { isAbsolute as isAbsolute10, join as join20, resolve as resolve10 } from
|
|
|
11441
11448
|
// package.json
|
|
11442
11449
|
var package_default = {
|
|
11443
11450
|
name: "@hasna/skills",
|
|
11444
|
-
version: "0.
|
|
11451
|
+
version: "0.9.2",
|
|
11445
11452
|
description: "Skills library for AI coding agents",
|
|
11446
11453
|
type: "module",
|
|
11447
11454
|
bin: {
|
|
@@ -15731,6 +15738,35 @@ function treeHash(root2) {
|
|
|
15731
15738
|
visit2(root2);
|
|
15732
15739
|
return hash2.digest("hex");
|
|
15733
15740
|
}
|
|
15741
|
+
function selectNativeMigrationTargets(inventory, manifest) {
|
|
15742
|
+
if (manifest.schema !== "hasna.skills-native-migration-targets.v1" || !/^[0-9a-f]{64}$/.test(manifest.digest) || !Array.isArray(manifest.targets) || manifest.targets.length === 0)
|
|
15743
|
+
throw new Error("Invalid native migration target manifest");
|
|
15744
|
+
const identities = new Set;
|
|
15745
|
+
const selected = [];
|
|
15746
|
+
for (const target of manifest.targets) {
|
|
15747
|
+
const projectRoot = resolve15(target.projectRoot), normalized = relative5(projectRoot, resolve15(projectRoot, target.path));
|
|
15748
|
+
if (!isAbsolute15(target.projectRoot) || projectRoot !== target.projectRoot || !existsSync11(projectRoot) || !lstatSync18(projectRoot).isDirectory())
|
|
15749
|
+
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
15750
|
+
assertSafePath(projectRoot);
|
|
15751
|
+
if (isAbsolute15(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep6}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
15752
|
+
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
15753
|
+
const identity3 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
15754
|
+
if (identities.has(identity3))
|
|
15755
|
+
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
15756
|
+
identities.add(identity3);
|
|
15757
|
+
const expected = resolve15(target.projectRoot, target.path);
|
|
15758
|
+
const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve15(entry2.path) === expected);
|
|
15759
|
+
if (matches.length !== 1)
|
|
15760
|
+
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
15761
|
+
const entry = matches[0];
|
|
15762
|
+
if (entry.bridge || entry.system || entry.vendor)
|
|
15763
|
+
throw new Error(`Native migration target is protected or vendor-owned: ${entry.path}`);
|
|
15764
|
+
if (entry.hash !== target.treeSha256 || treeHash(entry.path) !== target.treeSha256)
|
|
15765
|
+
throw new Error(`Native migration target changed after review: ${entry.path}`);
|
|
15766
|
+
selected.push(entry);
|
|
15767
|
+
}
|
|
15768
|
+
return selected;
|
|
15769
|
+
}
|
|
15734
15770
|
function projectAncestorDirectories(projects) {
|
|
15735
15771
|
const directories = new Set;
|
|
15736
15772
|
for (const project of projects) {
|
|
@@ -16219,12 +16255,13 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16219
16255
|
if (!expected || treeHash(entry.path) !== entry.hash || !isOwnedCliBridge(entry.path, [expected]))
|
|
16220
16256
|
throw new Error(`Skills bridge changed after planning: ${entry.path}`);
|
|
16221
16257
|
}
|
|
16222
|
-
const selected = inventory.filter((entry) => !entry.bridge && !entry.system && (entry.vendor ? options.includeVendor : entry.managed || options.includeUnmanaged));
|
|
16258
|
+
const selected = options.targetManifest ? selectNativeMigrationTargets(inventory, options.targetManifest) : inventory.filter((entry) => !entry.bridge && !entry.system && (entry.vendor ? options.includeVendor : entry.managed || options.includeUnmanaged));
|
|
16223
16259
|
for (const entry of selected)
|
|
16224
16260
|
if (treeHash(entry.path) !== entry.hash)
|
|
16225
16261
|
throw new Error(`Native skill changed after planning: ${entry.path}`);
|
|
16262
|
+
const targetManifest = options.targetManifest ? { schema: options.targetManifest.schema, digest: options.targetManifest.digest, targetCount: options.targetManifest.targets.length } : undefined;
|
|
16226
16263
|
if (!selected.length)
|
|
16227
|
-
return { entries: [], ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16264
|
+
return { entries: [], ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16228
16265
|
const operationId = randomUUID3(), archiveRoot = join25(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join25(archiveRoot, "receipt.json");
|
|
16229
16266
|
const entries = selected.map((entry, index) => ({
|
|
16230
16267
|
source: entry.vendor ? join25(entry.path, "SKILL.md") : entry.path,
|
|
@@ -16233,7 +16270,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16233
16270
|
...entry.vendor ? { discoveryOnly: true } : {},
|
|
16234
16271
|
status: "planned"
|
|
16235
16272
|
}));
|
|
16236
|
-
const journal = { version: 2, operationId, status: "planned", entries, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16273
|
+
const journal = { version: 2, operationId, status: "planned", entries, ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16237
16274
|
const moved = [];
|
|
16238
16275
|
const verifyArchive = (entry) => {
|
|
16239
16276
|
assertSafePath(entry.archive);
|
|
@@ -16327,7 +16364,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16327
16364
|
} catch {}
|
|
16328
16365
|
throw new Error(`Native archive failed; inspect the recovery journal at ${receiptPath} before retrying.`, { cause: error });
|
|
16329
16366
|
}
|
|
16330
|
-
return { entries: entries.map(({ status, conflict, ...entry }) => entry), receiptPath, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16367
|
+
return { entries: entries.map(({ status, conflict, ...entry }) => entry), receiptPath, ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16331
16368
|
}
|
|
16332
16369
|
function assertNativeExportAllowed(dataDir2 = getDataDirReadOnly()) {
|
|
16333
16370
|
if (requiresCliSkillLoading(dataDir2))
|
|
@@ -35954,6 +35991,8 @@ var remoteSkillSchema = exports_external.object({
|
|
|
35954
35991
|
tags: exports_external.array(exports_external.string()).optional(),
|
|
35955
35992
|
dependencies: exports_external.array(exports_external.string()).optional(),
|
|
35956
35993
|
version: exports_external.string().optional(),
|
|
35994
|
+
revisionId: exports_external.union([exports_external.string().regex(/^[\x21-\x7e]+$/), exports_external.null()]).optional(),
|
|
35995
|
+
lifecycle: exports_external.enum(["active", "archived"]).optional(),
|
|
35957
35996
|
availability: remoteAvailabilitySchema.optional()
|
|
35958
35997
|
}).passthrough().refine((skill) => skill.name || skill.slug, {
|
|
35959
35998
|
message: "Remote skill requires name or slug"
|
|
@@ -36016,6 +36055,8 @@ function normalizeRemoteSkill(skill) {
|
|
|
36016
36055
|
tags: skill.tags || ["remote"],
|
|
36017
36056
|
dependencies: skill.dependencies,
|
|
36018
36057
|
...skill.version ? { version: skill.version } : {},
|
|
36058
|
+
...skill.revisionId !== undefined ? { revisionId: skill.revisionId } : {},
|
|
36059
|
+
...skill.lifecycle ? { lifecycle: skill.lifecycle } : {},
|
|
36019
36060
|
availability: normalizeRemoteAvailability(skill.availability),
|
|
36020
36061
|
source: "remote"
|
|
36021
36062
|
};
|
|
@@ -37732,6 +37773,18 @@ class RemoteRequestError extends Error {
|
|
|
37732
37773
|
this.name = "RemoteRequestError";
|
|
37733
37774
|
}
|
|
37734
37775
|
}
|
|
37776
|
+
var KNOWN_SKILL_LIFECYCLE_CODES = new Set(["SKILL_ARCHIVE_PROFILE_CONFLICT", "LIFECYCLE_ROLE_REQUIRED"]);
|
|
37777
|
+
|
|
37778
|
+
class RemoteSkillLifecycleError extends RemoteRequestError {
|
|
37779
|
+
code;
|
|
37780
|
+
constructor(path, status, code) {
|
|
37781
|
+
super(path, status);
|
|
37782
|
+
this.name = "RemoteSkillLifecycleError";
|
|
37783
|
+
const safeCode = code !== undefined && KNOWN_SKILL_LIFECYCLE_CODES.has(code) ? code : undefined;
|
|
37784
|
+
this.code = safeCode;
|
|
37785
|
+
this.message = `Skill lifecycle update was refused (HTTP ${status}${safeCode ? `, code ${safeCode}` : ""})`;
|
|
37786
|
+
}
|
|
37787
|
+
}
|
|
37735
37788
|
|
|
37736
37789
|
class RemoteCreditCheckoutError extends RemoteRequestError {
|
|
37737
37790
|
code;
|
|
@@ -37912,6 +37965,39 @@ class RemoteSkillsClient {
|
|
|
37912
37965
|
})();
|
|
37913
37966
|
return this.capabilities;
|
|
37914
37967
|
}
|
|
37968
|
+
async addSkillPublishScope(keyId, expectedScopes, expectedOrgId) {
|
|
37969
|
+
if (!/^[A-Za-z0-9_-]+$/.test(keyId))
|
|
37970
|
+
throw new Error("Invalid API key id");
|
|
37971
|
+
if (!/^[A-Za-z0-9_-]{1,256}$/.test(expectedOrgId))
|
|
37972
|
+
throw new Error("Invalid expected organization id");
|
|
37973
|
+
if (!Array.isArray(expectedScopes) || expectedScopes.length > 32 || expectedScopes.some((scope) => typeof scope !== "string" || scope.length > 128 || !/^(?:\*|[a-z][a-z0-9_-]*:(?:\*|[a-z][a-z0-9_-]*))$/.test(scope)) || new Set(expectedScopes).size !== expectedScopes.length)
|
|
37974
|
+
throw new Error("Invalid expected API key scopes");
|
|
37975
|
+
const path = `/api/v1/admin/keys/${encodeURIComponent(keyId)}/scopes`;
|
|
37976
|
+
const response = await this.request(path, { method: "PATCH", body: JSON.stringify({ expected_scopes: expectedScopes, add_scopes: ["skills:publish"] }) });
|
|
37977
|
+
if (!response.ok)
|
|
37978
|
+
throw new RemoteRequestError(path, response.status);
|
|
37979
|
+
let value;
|
|
37980
|
+
try {
|
|
37981
|
+
value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readBoundedResponse(response, 64 * 1024)));
|
|
37982
|
+
} catch {
|
|
37983
|
+
throw new Error("Invalid API key scope update response");
|
|
37984
|
+
}
|
|
37985
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
37986
|
+
throw new Error("Invalid API key scope update response");
|
|
37987
|
+
const body = value;
|
|
37988
|
+
const returnedId = body.keyId;
|
|
37989
|
+
const orgId = body.orgId;
|
|
37990
|
+
const scopes = body.scopes;
|
|
37991
|
+
if (returnedId !== keyId || typeof orgId !== "string" || !orgId || expectedOrgId !== undefined && orgId !== expectedOrgId || !Array.isArray(scopes) || scopes.some((scope) => typeof scope !== "string") || body.updated !== true) {
|
|
37992
|
+
throw new Error("Invalid API key scope update response");
|
|
37993
|
+
}
|
|
37994
|
+
const returnedScopes = scopes;
|
|
37995
|
+
const expectedResult = expectedScopes.includes("skills:publish") ? expectedScopes : [...expectedScopes, "skills:publish"];
|
|
37996
|
+
if (returnedScopes.length !== expectedResult.length || expectedResult.some((scope, index) => returnedScopes[index] !== scope)) {
|
|
37997
|
+
throw new Error("API key scope update response did not preserve the expected scopes");
|
|
37998
|
+
}
|
|
37999
|
+
return { keyId, orgId, scopes: [...returnedScopes], updated: true };
|
|
38000
|
+
}
|
|
37915
38001
|
async submitQuotedRun(slug2, input2 = {}, args = [], approval = {}) {
|
|
37916
38002
|
runQuoteReceipt(approval.quoteReceipt);
|
|
37917
38003
|
({ input: input2, args, approval } = JSON.parse(JSON.stringify({ input: input2, args, approval })));
|
|
@@ -38429,6 +38515,19 @@ class RemoteSkillsClient {
|
|
|
38429
38515
|
async deleteSkill(slug2) {
|
|
38430
38516
|
return this.request(`/api/v1/skills/${encodeURIComponent(slug2)}`, { method: "DELETE" });
|
|
38431
38517
|
}
|
|
38518
|
+
async setSkillLifecycle(slug2, lifecycle, options) {
|
|
38519
|
+
const path = `/api/v1/skills/${encodeURIComponent(slug2)}/lifecycle`;
|
|
38520
|
+
const response = await this.request(path, {
|
|
38521
|
+
method: "PATCH",
|
|
38522
|
+
headers: { "If-Match": options.expectedRevisionId },
|
|
38523
|
+
body: JSON.stringify({ lifecycle, ...options.reason ? { reason: options.reason } : {}, ...options.replacementSlug ? { replacementSlug: options.replacementSlug } : {} })
|
|
38524
|
+
});
|
|
38525
|
+
if (!response.ok) {
|
|
38526
|
+
const code = await readResponseCode(response);
|
|
38527
|
+
throw new RemoteSkillLifecycleError(path, response.status, code);
|
|
38528
|
+
}
|
|
38529
|
+
return response.json();
|
|
38530
|
+
}
|
|
38432
38531
|
async downloadSkillBundle(slug2) {
|
|
38433
38532
|
return this.request(`/api/v1/skills/${encodeURIComponent(slug2)}/bundle`, { method: "GET" });
|
|
38434
38533
|
}
|
|
@@ -38581,9 +38680,13 @@ function normalizeSkillSummaryList(payload) {
|
|
|
38581
38680
|
return payload.map(normalizeSkillSummary);
|
|
38582
38681
|
}
|
|
38583
38682
|
async function responseBodyCarriesCode(response, codes) {
|
|
38683
|
+
const code = await readResponseCode(response);
|
|
38684
|
+
return code !== undefined && codes.includes(code);
|
|
38685
|
+
}
|
|
38686
|
+
async function readResponseCode(response) {
|
|
38584
38687
|
const reader = response.body?.getReader();
|
|
38585
38688
|
if (!reader)
|
|
38586
|
-
return
|
|
38689
|
+
return;
|
|
38587
38690
|
const maximum = 8 * 1024;
|
|
38588
38691
|
let deadline;
|
|
38589
38692
|
const expired = new Promise((_, reject) => {
|
|
@@ -38598,7 +38701,7 @@ async function responseBodyCarriesCode(response, codes) {
|
|
|
38598
38701
|
break;
|
|
38599
38702
|
size += next.value.byteLength;
|
|
38600
38703
|
if (size > maximum)
|
|
38601
|
-
return
|
|
38704
|
+
return;
|
|
38602
38705
|
chunks.push(next.value);
|
|
38603
38706
|
}
|
|
38604
38707
|
const bytes = new Uint8Array(size);
|
|
@@ -38609,11 +38712,11 @@ async function responseBodyCarriesCode(response, codes) {
|
|
|
38609
38712
|
}
|
|
38610
38713
|
const payload = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
38611
38714
|
if (!payload || typeof payload !== "object" || Array.isArray(payload) || !Object.hasOwn(payload, "code"))
|
|
38612
|
-
return
|
|
38715
|
+
return;
|
|
38613
38716
|
const code = payload.code;
|
|
38614
|
-
return typeof code === "string" &&
|
|
38717
|
+
return typeof code === "string" && /^[A-Z][A-Z0-9_:-]{0,127}$/.test(code) ? code : undefined;
|
|
38615
38718
|
} catch {
|
|
38616
|
-
return
|
|
38719
|
+
return;
|
|
38617
38720
|
} finally {
|
|
38618
38721
|
clearTimeout(deadline);
|
|
38619
38722
|
reader.cancel().catch(() => {});
|
|
@@ -38847,7 +38950,7 @@ function recordScheduleRun(id, status, targetDir) {
|
|
|
38847
38950
|
import { createHash as createHash17 } from "crypto";
|
|
38848
38951
|
var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
38849
38952
|
function revisionIdOf(content) {
|
|
38850
|
-
const
|
|
38953
|
+
const canonicalContent = {
|
|
38851
38954
|
slug: content.slug,
|
|
38852
38955
|
displayName: content.displayName,
|
|
38853
38956
|
description: content.description,
|
|
@@ -38859,7 +38962,13 @@ function revisionIdOf(content) {
|
|
|
38859
38962
|
skillMd: content.skillMd ?? null,
|
|
38860
38963
|
bundleSha256: content.bundleSha256 ?? null,
|
|
38861
38964
|
bundleByteSize: content.bundleByteSize ?? null
|
|
38862
|
-
}
|
|
38965
|
+
};
|
|
38966
|
+
if (content.lifecycle === "archived" || content.archiveReason !== undefined || content.replacementSlug !== undefined) {
|
|
38967
|
+
canonicalContent.lifecycle = content.lifecycle ?? "active";
|
|
38968
|
+
canonicalContent.archiveReason = content.archiveReason ?? null;
|
|
38969
|
+
canonicalContent.replacementSlug = content.replacementSlug ?? null;
|
|
38970
|
+
}
|
|
38971
|
+
const canonical4 = JSON.stringify(canonicalContent);
|
|
38863
38972
|
return createHash17("sha256").update(canonical4).digest("hex");
|
|
38864
38973
|
}
|
|
38865
38974
|
function revisionIdOfRecord(record7) {
|
|
@@ -22,6 +22,17 @@ export interface NativeSkillEntry {
|
|
|
22
22
|
bridgeHome?: string;
|
|
23
23
|
rootAlias?: AgentRootAlias;
|
|
24
24
|
}
|
|
25
|
+
export interface NativeMigrationTarget {
|
|
26
|
+
agent: string;
|
|
27
|
+
projectRoot: string;
|
|
28
|
+
path: string;
|
|
29
|
+
treeSha256: string;
|
|
30
|
+
}
|
|
31
|
+
export interface NativeMigrationTargetManifest {
|
|
32
|
+
schema: "hasna.skills-native-migration-targets.v1";
|
|
33
|
+
targets: NativeMigrationTarget[];
|
|
34
|
+
digest: string;
|
|
35
|
+
}
|
|
25
36
|
export interface AgentConfigChange {
|
|
26
37
|
path: string;
|
|
27
38
|
before: string | null;
|
|
@@ -40,6 +51,15 @@ export interface AgentIntegrationPlan {
|
|
|
40
51
|
discoveryAfter?: AgentDiscoveryBinding[];
|
|
41
52
|
rootAliases?: AgentRootAlias[];
|
|
42
53
|
}
|
|
54
|
+
/** Parse the reviewed exact-target binding used by native migration. Paths are
|
|
55
|
+
* deliberately project-relative so a manifest cannot silently select another
|
|
56
|
+
* checkout when a project root changes. */
|
|
57
|
+
export declare function parseNativeMigrationTargetManifest(input: string | Buffer): NativeMigrationTargetManifest;
|
|
58
|
+
/** Read a manifest without following links or opening special files, with a
|
|
59
|
+
* finite bound so a CLI cannot block on an untrusted path. */
|
|
60
|
+
export declare function readNativeMigrationTargetManifest(path: string): NativeMigrationTargetManifest;
|
|
61
|
+
/** Validate every reviewed target before any archive directory or journal is created. */
|
|
62
|
+
export declare function selectNativeMigrationTargets(inventory: NativeSkillEntry[], manifest: NativeMigrationTargetManifest): NativeSkillEntry[];
|
|
43
63
|
export declare function inventoryNativeSkills(home?: string, options?: {
|
|
44
64
|
includeVendor?: boolean;
|
|
45
65
|
guardHermes?: boolean;
|
|
@@ -75,6 +95,7 @@ export declare function archiveNativeSkills(inventory: NativeSkillEntry[], optio
|
|
|
75
95
|
includeUnmanaged?: boolean;
|
|
76
96
|
includeVendor?: boolean;
|
|
77
97
|
allowRootAliases?: boolean;
|
|
98
|
+
targetManifest?: NativeMigrationTargetManifest;
|
|
78
99
|
}): {
|
|
79
100
|
entries: Array<{
|
|
80
101
|
source: string;
|
|
@@ -84,6 +105,11 @@ export declare function archiveNativeSkills(inventory: NativeSkillEntry[], optio
|
|
|
84
105
|
}>;
|
|
85
106
|
receiptPath?: string;
|
|
86
107
|
rootAliases?: AgentRootAlias[];
|
|
108
|
+
targetManifest?: {
|
|
109
|
+
schema: string;
|
|
110
|
+
digest: string;
|
|
111
|
+
targetCount: number;
|
|
112
|
+
};
|
|
87
113
|
};
|
|
88
114
|
/** Run before any prompt context load. Missing ownership or reappearing native
|
|
89
115
|
* discovery files require repair; verified cache availability is not an override. */
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
import type { PureExecutionContract } from "../sdk/execution/types.js";
|
|
2
|
+
export interface CloudEligibility {
|
|
3
|
+
contractVersion: 1;
|
|
4
|
+
eligible: boolean;
|
|
5
|
+
skill: string;
|
|
6
|
+
version: string;
|
|
7
|
+
bundleDigest: string;
|
|
8
|
+
reason?: string;
|
|
9
|
+
runtimeImageDigest?: string;
|
|
10
|
+
executionContract?: PureExecutionContract | {
|
|
11
|
+
id: "pdf.v1";
|
|
12
|
+
};
|
|
13
|
+
secrets?: "none";
|
|
14
|
+
egress?: "deny";
|
|
15
|
+
}
|
|
1
16
|
export interface CloudExecution {
|
|
2
17
|
contractVersion: 1;
|
|
3
18
|
id: string;
|
|
@@ -7,6 +22,9 @@ export interface CloudExecution {
|
|
|
7
22
|
bundleDigest: string;
|
|
8
23
|
inputDigest: string;
|
|
9
24
|
runtimeImageDigest: string;
|
|
25
|
+
executionContract?: PureExecutionContract | {
|
|
26
|
+
id: "pdf.v1";
|
|
27
|
+
};
|
|
10
28
|
status: "admitted" | "leased" | "running" | "succeeded" | "failed" | "cancelled";
|
|
11
29
|
exitCode?: number;
|
|
12
30
|
artifacts: {
|
|
@@ -22,6 +40,8 @@ export declare class CloudExecutionClient {
|
|
|
22
40
|
constructor(apiOrigin: string, apiKey: string);
|
|
23
41
|
static configured(): Promise<CloudExecutionClient>;
|
|
24
42
|
private request;
|
|
43
|
+
/** Metadata only: never creates, starts or reconciles a task. */
|
|
44
|
+
eligibility(slug: string, version: string, bundleDigest?: string): Promise<CloudEligibility>;
|
|
25
45
|
submit(slug: string, version: string, input: unknown, key: string, selection?: {
|
|
26
46
|
bundleDigest: string;
|
|
27
47
|
workspaceId?: string;
|
|
@@ -12,6 +12,9 @@ export interface SkillMeta {
|
|
|
12
12
|
tags: string[];
|
|
13
13
|
dependencies?: string[];
|
|
14
14
|
version?: string;
|
|
15
|
+
/** Server registry revision and lifecycle, when supplied by a remote read. */
|
|
16
|
+
revisionId?: string | null;
|
|
17
|
+
lifecycle?: "active" | "archived";
|
|
15
18
|
/**
|
|
16
19
|
* Artifact class of the skill. "executable" skills carry a runnable
|
|
17
20
|
* package.json/bin/src; "instruction" skills are SKILL.md-primary prose for
|
|
@@ -30,6 +30,10 @@ export declare class RemoteRequestError extends Error {
|
|
|
30
30
|
readonly status: number;
|
|
31
31
|
constructor(path: string, status: number, _statusText?: string);
|
|
32
32
|
}
|
|
33
|
+
export declare class RemoteSkillLifecycleError extends RemoteRequestError {
|
|
34
|
+
readonly code?: string;
|
|
35
|
+
constructor(path: string, status: number, code?: string);
|
|
36
|
+
}
|
|
33
37
|
/** Bounded checkout outcome; the key is caller-owned, never copied from a server error. */
|
|
34
38
|
export declare class RemoteCreditCheckoutError extends RemoteRequestError {
|
|
35
39
|
readonly code: RemoteCreditCheckoutErrorCode;
|
|
@@ -144,6 +148,8 @@ export declare class RemoteSkillsClient {
|
|
|
144
148
|
};
|
|
145
149
|
recurringConsents?: RecurringCapability;
|
|
146
150
|
}>;
|
|
151
|
+
/** Add the single supported publication scope to an existing key, metadata only. */
|
|
152
|
+
addSkillPublishScope(keyId: string, expectedScopes: string[], expectedOrgId: string): Promise<Record<string, unknown>>;
|
|
147
153
|
/** Quote first and fail closed when the caller has not approved the required credits. */
|
|
148
154
|
submitQuotedRun(slug: string, input?: Record<string, unknown>, args?: string[], approval?: RemoteRunApproval): Promise<RemoteSkillRunContract>;
|
|
149
155
|
getIdentity(): Promise<Record<string, unknown>>;
|
|
@@ -252,6 +258,11 @@ export declare class RemoteSkillsClient {
|
|
|
252
258
|
*/
|
|
253
259
|
publishSkill(manifest: Record<string, unknown>, bundle?: Uint8Array, ifMatch?: string): Promise<Response>;
|
|
254
260
|
deleteSkill(slug: string): Promise<Response>;
|
|
261
|
+
setSkillLifecycle(slug: string, lifecycle: "active" | "archived", options: {
|
|
262
|
+
reason?: string;
|
|
263
|
+
replacementSlug?: string;
|
|
264
|
+
expectedRevisionId: string;
|
|
265
|
+
}): Promise<any>;
|
|
255
266
|
downloadSkillBundle(slug: string): Promise<Response>;
|
|
256
267
|
/**
|
|
257
268
|
* Bundle fetch for the verified-pull path. Returns the raw Response so the caller can
|
package/dist/lib/revision.d.ts
CHANGED
|
@@ -12,6 +12,9 @@ export interface RevisionContent {
|
|
|
12
12
|
skillMd?: string;
|
|
13
13
|
bundleSha256?: string;
|
|
14
14
|
bundleByteSize?: number;
|
|
15
|
+
lifecycle?: "active" | "archived";
|
|
16
|
+
archiveReason?: string;
|
|
17
|
+
replacementSlug?: string;
|
|
15
18
|
}
|
|
16
19
|
export declare function revisionIdOf(content: RevisionContent): string;
|
|
17
20
|
export declare function revisionIdOfRecord(record: RevisionContent): string;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { ImageProfileRegistry } from "./image-profile.js";
|
|
12
12
|
import type { RunExecutionStore } from "./storage.js";
|
|
13
|
-
import { type FrozenAdmission, type RunLimits, type RunPolicy, type RuntimeName } from "./types.js";
|
|
13
|
+
import { type FrozenAdmission, type RunLimits, type RunPolicy, type RuntimeName, type PureExecutionContract } from "./types.js";
|
|
14
14
|
export interface SubmitRunInput {
|
|
15
15
|
tenantId: string;
|
|
16
16
|
skillId: string;
|
|
@@ -24,6 +24,7 @@ export interface SubmitRunInput {
|
|
|
24
24
|
systemDeps?: string[];
|
|
25
25
|
policy?: Partial<RunPolicy>;
|
|
26
26
|
limits?: Partial<RunLimits>;
|
|
27
|
+
executionContract?: PureExecutionContract;
|
|
27
28
|
}
|
|
28
29
|
export interface SubmitRunResult {
|
|
29
30
|
run: FrozenAdmission;
|
|
@@ -33,6 +33,13 @@ export interface RunLimits {
|
|
|
33
33
|
maxArtifactsBytes: number;
|
|
34
34
|
maxConcurrency: number;
|
|
35
35
|
}
|
|
36
|
+
/** Trusted, versioned adapter identity. Absent only for legacy PDF admissions. */
|
|
37
|
+
export interface PureExecutionContract {
|
|
38
|
+
id: "regex-test.v1";
|
|
39
|
+
descriptorDigest: string;
|
|
40
|
+
entrypoint: string;
|
|
41
|
+
entrypointDigest: string;
|
|
42
|
+
}
|
|
36
43
|
/** Everything frozen at admission under one stable run_id. */
|
|
37
44
|
export interface FrozenAdmission {
|
|
38
45
|
contractVersion: number;
|
|
@@ -46,6 +53,7 @@ export interface FrozenAdmission {
|
|
|
46
53
|
runtimeImageDigest: string;
|
|
47
54
|
/** Prebuilt dependency layer tag, when the manifest's system_deps are allowlisted. */
|
|
48
55
|
dependencyLayerTag: string | null;
|
|
56
|
+
executionContract?: PureExecutionContract;
|
|
49
57
|
/** sha256 of the canonical serialization of the run input. */
|
|
50
58
|
inputDigest: string;
|
|
51
59
|
runtime: RuntimeName;
|
|
@@ -109,6 +117,7 @@ export interface AttemptReceipt {
|
|
|
109
117
|
runtimeImageDigest: string;
|
|
110
118
|
bundleDigest: string;
|
|
111
119
|
dependencyLayerTag: string | null;
|
|
120
|
+
executionContract?: PureExecutionContract;
|
|
112
121
|
policy: RunPolicy;
|
|
113
122
|
limits: RunLimits;
|
|
114
123
|
exitCode: number | null;
|
package/dist/sdk/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* — the shared @hasna/contracts ladder — instead of reading an environment
|
|
16
16
|
* variable of its own. See lib/fleet-credentials.ts.
|
|
17
17
|
*/
|
|
18
|
+
export { CloudExecutionClient, type CloudExecution, type CloudEligibility } from "../lib/cloud-executions.js";
|
|
18
19
|
export { readExecutionGrantPolicy, saveExecutionGrantPolicy, resolveExecutionGrant } from "../lib/execution-grant-client.js";
|
|
19
20
|
export type { ExecutionGrant, ExecutionGrantPolicy, ExecutionGrantRequest, ResolvedExecutionGrant } from "../lib/execution-grants.js";
|
|
20
21
|
export { HttpProfileClient, createProfileClient, type ProfileClient, type AuthenticatedProfilePrincipal, type AuthenticatedProfileRole } from "../lib/profile-client.js";
|