@hasna/skills 0.10.76 → 0.10.78
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 +45 -3
- package/bin/index.js +748 -339
- package/bin/mcp.js +200 -32
- package/bin/migrate.js +1 -1
- package/bin/server.js +36 -33
- package/bin/worker.js +4 -1
- package/dist/cli/commands/runtime-mcp.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +113 -21
- package/dist/lib/auth-store.d.ts +1 -1
- package/dist/lib/codex-plugin-capability-paths.d.ts +31 -0
- package/dist/lib/credential-profile-command.d.ts +5 -0
- package/dist/lib/fleet-credentials.d.ts +11 -5
- package/dist/lib/instance-credentials.d.ts +2 -0
- package/dist/lib/mcp-registration-environment.d.ts +2 -0
- package/dist/lib/private-publication-customer.d.ts +6 -2
- package/dist/lib/registry-types.d.ts +2 -0
- package/dist/lib/remote-private-publications.d.ts +22 -0
- package/dist/lib/sign-in.d.ts +1 -1
- package/dist/runtime-prerequisites.js +3 -2
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +215 -127
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -23,7 +23,7 @@ var package_default;
|
|
|
23
23
|
var init_package = __esm(() => {
|
|
24
24
|
package_default = {
|
|
25
25
|
name: "@hasna/skills",
|
|
26
|
-
version: "0.10.
|
|
26
|
+
version: "0.10.78",
|
|
27
27
|
description: "Skills library for AI coding agents",
|
|
28
28
|
type: "module",
|
|
29
29
|
bin: {
|
|
@@ -1087,6 +1087,10 @@ function skillsFileHasCredential(file) {
|
|
|
1087
1087
|
return false;
|
|
1088
1088
|
return /^\s*(?:export\s+)?(?:HASNA_SKILLS_API_KEY|SKILLS_API_KEY|HASNA_SKILLS_API_KEY_REF)\s*=\s*\S/m.test(text);
|
|
1089
1089
|
}
|
|
1090
|
+
function skillsFileHasVaultReference(file) {
|
|
1091
|
+
const text = readMetadataText(file);
|
|
1092
|
+
return text !== null && /^\s*(?:export\s+)?HASNA_SKILLS_API_KEY_REF\s*=\s*\S/m.test(text);
|
|
1093
|
+
}
|
|
1090
1094
|
var SKILLS_BOUND_API_URL = "HASNA_SKILLS_BOUND_API_URL";
|
|
1091
1095
|
var init_instance_credentials = __esm(() => {
|
|
1092
1096
|
init_transport();
|
|
@@ -1121,6 +1125,20 @@ var init_local_opt_in = __esm(() => {
|
|
|
1121
1125
|
// src/lib/product-default.ts
|
|
1122
1126
|
var SKILLS_PRODUCT_DEFAULT_ORIGIN = "https://skills.md";
|
|
1123
1127
|
|
|
1128
|
+
// src/lib/credential-profile-command.ts
|
|
1129
|
+
function skillsShellArgument(value) {
|
|
1130
|
+
return /^[A-Za-z0-9._:/-]+$/.test(value) ? value : `'${value.replace(/'/g, "'\\''")}'`;
|
|
1131
|
+
}
|
|
1132
|
+
function skillsApiUrlEnvironment(origin) {
|
|
1133
|
+
return urlKeys.map((name) => `${name}=${skillsShellArgument(origin)}`).join(" ");
|
|
1134
|
+
}
|
|
1135
|
+
var urlKeys;
|
|
1136
|
+
var init_credential_profile_command = __esm(() => {
|
|
1137
|
+
init_instance_credentials();
|
|
1138
|
+
init_transport();
|
|
1139
|
+
urlKeys = clientTransportEnvKeys("skills").apiUrlKeys;
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1124
1142
|
// src/lib/fleet-credentials.ts
|
|
1125
1143
|
var exports_fleet_credentials = {};
|
|
1126
1144
|
__export(exports_fleet_credentials, {
|
|
@@ -1145,6 +1163,8 @@ __export(exports_fleet_credentials, {
|
|
|
1145
1163
|
gatewaySignInRefusal: () => gatewaySignInRefusal,
|
|
1146
1164
|
credentialPairing: () => credentialPairing,
|
|
1147
1165
|
configuredSkillsApiUrl: () => configuredSkillsApiUrl,
|
|
1166
|
+
captureSkillsSignInTarget: () => captureSkillsSignInTarget,
|
|
1167
|
+
assertSkillsSignInCredentialReplaceable: () => assertSkillsSignInCredentialReplaceable,
|
|
1148
1168
|
SkillsFleetCredentialError: () => SkillsFleetCredentialError,
|
|
1149
1169
|
SKILLS_LOCAL_OPT_IN_ENV_KEYS: () => SKILLS_LOCAL_OPT_IN_ENV_KEYS,
|
|
1150
1170
|
SKILLS_CREDENTIAL_TIERS: () => SKILLS_CREDENTIAL_TIERS,
|
|
@@ -1450,8 +1470,24 @@ function gatewaySignInRefusal(target) {
|
|
|
1450
1470
|
if (normalizeSkillsApiOrigin(target.origin) !== normalizeSkillsApiOrigin(defaultFleetGatewayBaseUrl(SKILLS_APP)))
|
|
1451
1471
|
return null;
|
|
1452
1472
|
const cause = target.credentialSource ? `${target.credentialSource} holds a Skills credential for the internal gateway` : target.source === "--url" ? "--url names the internal gateway" : `${target.source} selects the internal gateway`;
|
|
1453
|
-
const
|
|
1454
|
-
return new SkillsFleetCredentialError(`${cause}, which has no sign-in service. Nothing was sent
|
|
1473
|
+
const command = (SKILLS_API_URL_ENV_KEYS.includes(target.source) ? `${skillsApiUrlEnvironment(SKILLS_PRODUCT_DEFAULT_ORIGIN)} ` : "") + "skills --profile <new-profile> login";
|
|
1474
|
+
return new SkillsFleetCredentialError(`${cause}, which has no sign-in service. Nothing was sent. ` + `Keep the fleet configuration and use a separate profile for product sign-in: ${command}.`, "GATEWAY_AUTH_UNAVAILABLE", [command]);
|
|
1475
|
+
}
|
|
1476
|
+
function assertSkillsSignInCredentialReplaceable(env = process.env, profile) {
|
|
1477
|
+
const files = skillsProfileCredentialFiles(env, profile);
|
|
1478
|
+
const verifyUnchanged = captureSkillsCredentialFiles(files);
|
|
1479
|
+
const gateway = normalizeSkillsApiOrigin(defaultFleetGatewayBaseUrl(SKILLS_APP));
|
|
1480
|
+
const command = (SKILLS_API_URL_ENV_KEYS.some((name) => env[name]?.trim()) ? `${skillsApiUrlEnvironment(SKILLS_PRODUCT_DEFAULT_ORIGIN)} ` : "") + "skills --profile <new-profile> login";
|
|
1481
|
+
for (const file of files) {
|
|
1482
|
+
if (!skillsFileHasCredential(file))
|
|
1483
|
+
continue;
|
|
1484
|
+
const metadata = readSkillsInstanceMetadata(file);
|
|
1485
|
+
const instance = metadata.binding ?? metadata.apiUrl;
|
|
1486
|
+
if (skillsFileHasVaultReference(file) || !instance || normalizeSkillsApiOrigin(instance) === gateway) {
|
|
1487
|
+
throw new SkillsFleetCredentialError("The selected profile contains a protected fleet credential or vault reference. Nothing was sent or changed. " + `Use a separate profile for product sign-in: ${command}.`, "STORED_CREDENTIAL_PROTECTED", [command]);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
verifyUnchanged();
|
|
1455
1491
|
}
|
|
1456
1492
|
function explicitSignInOrigin(url) {
|
|
1457
1493
|
if (!url.trim() || /[\x00-\x1f\x7f]/.test(url)) {
|
|
@@ -1479,13 +1515,15 @@ function resolveSkillsSignInOrigin(env = process.env, options = {}, explicitUrl)
|
|
|
1479
1515
|
const snapshot = snapshotSkillsEnvironment(env);
|
|
1480
1516
|
const resolvedOptions = snapshotSkillsOptions(env, options);
|
|
1481
1517
|
const profile = resolvedOptions.credentials?.profile;
|
|
1518
|
+
assertSkillsSignInCredentialReplaceable(snapshot, profile);
|
|
1482
1519
|
const configured = configuredSkillsApiUrl(snapshot, resolvedOptions.credentials?.keychain, profile);
|
|
1483
1520
|
const declared = configured && configured.source !== "default" ? configured : null;
|
|
1484
1521
|
if (explicitUrl !== undefined) {
|
|
1485
1522
|
const origin = explicitSignInOrigin(explicitUrl);
|
|
1486
1523
|
const storedHere = declared ? skillsProfileCredentialFiles(snapshot, profile).includes(declared.source) : false;
|
|
1487
1524
|
if (declared && !storedHere && normalizeSkillsApiOrigin(declared.value) !== origin) {
|
|
1488
|
-
|
|
1525
|
+
const command = `${skillsApiUrlEnvironment(origin)} skills --profile <new-profile> login`;
|
|
1526
|
+
throw new SkillsFleetCredentialError(`--url ${origin} conflicts with ${declared.source}, which outranks the saved configuration and would ` + `shadow the key this sign-in stores. Keep the existing configuration and use a separate process and profile: ${command}.`, "INVALID_API_URL", [command]);
|
|
1489
1527
|
}
|
|
1490
1528
|
return { origin, source: "--url" };
|
|
1491
1529
|
}
|
|
@@ -1517,6 +1555,14 @@ function resolveSkillsSignInOrigin(env = process.env, options = {}, explicitUrl)
|
|
|
1517
1555
|
throw error;
|
|
1518
1556
|
}
|
|
1519
1557
|
}
|
|
1558
|
+
function captureSkillsSignInTarget(env = process.env, options = {}, explicitUrl) {
|
|
1559
|
+
const snapshot = snapshotSkillsEnvironment(env);
|
|
1560
|
+
const profile = options.credentials?.profile ?? selectedCliSkillsCredentialProfile();
|
|
1561
|
+
const unchanged2 = captureSkillsCredentialFiles(skillsProfileCredentialFiles(snapshot, profile));
|
|
1562
|
+
const target = resolveSkillsSignInOrigin(env, options, explicitUrl);
|
|
1563
|
+
unchanged2();
|
|
1564
|
+
return { ...target, unchanged: unchanged2 };
|
|
1565
|
+
}
|
|
1520
1566
|
function requireSkillsFleet(action = "This command", env = process.env, options = {}) {
|
|
1521
1567
|
const fleet = resolveSkillsFleet(env, options);
|
|
1522
1568
|
if (fleet.mode === "hosted")
|
|
@@ -1528,6 +1574,7 @@ var init_fleet_credentials = __esm(() => {
|
|
|
1528
1574
|
init_transport();
|
|
1529
1575
|
init_instance_credentials();
|
|
1530
1576
|
init_local_opt_in();
|
|
1577
|
+
init_credential_profile_command();
|
|
1531
1578
|
init_local_opt_in();
|
|
1532
1579
|
ENV_KEYS = clientTransportEnvKeys(SKILLS_APP);
|
|
1533
1580
|
SKILLS_API_URL_ENV_KEYS = ENV_KEYS.apiUrlKeys;
|
|
@@ -22758,7 +22805,8 @@ var init_codex_native_compatibility = __esm(() => {
|
|
|
22758
22805
|
"codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
22759
22806
|
"codex-cli 0.161.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
22760
22807
|
"codex-cli 0.162.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
22761
|
-
"codex-cli 0.162.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
22808
|
+
"codex-cli 0.162.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
22809
|
+
"codex-cli 0.163.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
22762
22810
|
};
|
|
22763
22811
|
SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version2) => supportsCodexNativeCapability(version2, "hooks")));
|
|
22764
22812
|
});
|
|
@@ -32251,6 +32299,40 @@ var init_codex_settings_witness_v1 = __esm(() => {
|
|
|
32251
32299
|
VERBOSITY = new Set(["low", "medium", "high"]);
|
|
32252
32300
|
});
|
|
32253
32301
|
|
|
32302
|
+
// src/lib/codex-plugin-capability-paths.ts
|
|
32303
|
+
function foldCodexPluginEntryName(name) {
|
|
32304
|
+
return name.toUpperCase().toLowerCase();
|
|
32305
|
+
}
|
|
32306
|
+
function codexPluginRootCapabilityEntry(name) {
|
|
32307
|
+
const folded = foldCodexPluginEntryName(name);
|
|
32308
|
+
return CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES.includes(folded) ? folded : null;
|
|
32309
|
+
}
|
|
32310
|
+
function isCodexSkillDocumentName(name) {
|
|
32311
|
+
return foldCodexPluginEntryName(name) === "skill.md";
|
|
32312
|
+
}
|
|
32313
|
+
var CODEX_PLUGIN_MANIFEST_LOCATIONS, CODEX_PLUGIN_MANIFEST_DIRECTORIES, CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES;
|
|
32314
|
+
var init_codex_plugin_capability_paths = __esm(() => {
|
|
32315
|
+
CODEX_PLUGIN_MANIFEST_LOCATIONS = Object.freeze([
|
|
32316
|
+
"plugin.json",
|
|
32317
|
+
".codex-plugin/plugin.json",
|
|
32318
|
+
".claude-plugin/plugin.json",
|
|
32319
|
+
".cursor-plugin/plugin.json"
|
|
32320
|
+
]);
|
|
32321
|
+
CODEX_PLUGIN_MANIFEST_DIRECTORIES = Object.freeze([".codex-plugin", ".claude-plugin", ".cursor-plugin"]);
|
|
32322
|
+
CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES = Object.freeze([
|
|
32323
|
+
"plugin.json",
|
|
32324
|
+
".codex-plugin",
|
|
32325
|
+
".claude-plugin",
|
|
32326
|
+
".cursor-plugin",
|
|
32327
|
+
"hooks",
|
|
32328
|
+
"hooks.json",
|
|
32329
|
+
".mcp.json",
|
|
32330
|
+
".app.json",
|
|
32331
|
+
"commands",
|
|
32332
|
+
"agents"
|
|
32333
|
+
]);
|
|
32334
|
+
});
|
|
32335
|
+
|
|
32254
32336
|
// src/lib/codex-hook-mcp-dependencies.ts
|
|
32255
32337
|
import { createHash as createHash12 } from "crypto";
|
|
32256
32338
|
import { basename as basename7, dirname as dirname12, isAbsolute as isAbsolute12, join as join16, resolve as resolve11, sep as sep5 } from "path";
|
|
@@ -32395,15 +32477,13 @@ function captureCodexHookMcpDependencies(configPath, reviewed, configText, chang
|
|
|
32395
32477
|
}
|
|
32396
32478
|
};
|
|
32397
32479
|
const root = join16(cacheRoot, identity2, selectCodexPluginVersion(versions2, selectionBudget));
|
|
32398
|
-
const
|
|
32480
|
+
const [agentPluginManifest, ...legacyManifests] = CODEX_PLUGIN_MANIFEST_LOCATIONS;
|
|
32481
|
+
const agent = read(join16(root, agentPluginManifest));
|
|
32399
32482
|
if (agent !== null) {
|
|
32400
32483
|
const schema = JSON.parse(agent).$schema;
|
|
32401
32484
|
need5(typeof schema !== "string" || !schema.startsWith("https://agent-plugins.org/schemas/"));
|
|
32402
32485
|
}
|
|
32403
|
-
const
|
|
32404
|
-
const claude = read(join16(root, ".claude-plugin/plugin.json"));
|
|
32405
|
-
const cursor = read(join16(root, ".cursor-plugin/plugin.json"));
|
|
32406
|
-
const text2 = codex ?? claude ?? cursor;
|
|
32486
|
+
const text2 = legacyManifests.map((location) => read(join16(root, location))).find((value) => value !== null) ?? null;
|
|
32407
32487
|
if (text2 === null)
|
|
32408
32488
|
continue;
|
|
32409
32489
|
const manifest = JSON.parse(text2);
|
|
@@ -32425,6 +32505,7 @@ var init_codex_hook_mcp_dependencies = __esm(() => {
|
|
|
32425
32505
|
init_claude_settings_witness();
|
|
32426
32506
|
init_agent_discovery_directories();
|
|
32427
32507
|
init_agent_discovery_bytes();
|
|
32508
|
+
init_codex_plugin_capability_paths();
|
|
32428
32509
|
events = new Set(["PreToolUse", "PermissionRequest", "PostToolUse", "PreCompact", "PostCompact", "SessionStart", "SessionEnd", "UserPromptSubmit", "SubagentStart", "SubagentStop", "Stop", "Interrupt"]);
|
|
32429
32510
|
});
|
|
32430
32511
|
|
|
@@ -34007,9 +34088,10 @@ var CODEX_VENDOR_MARKETPLACES, CODEX_REMOTE_VENDOR_MARKETPLACES, OTHER_PLUGIN_CO
|
|
|
34007
34088
|
var init_codex_vendor_refresh = __esm(() => {
|
|
34008
34089
|
init_claude_settings_witness();
|
|
34009
34090
|
init_codex_plugin_skill_controls();
|
|
34091
|
+
init_codex_plugin_capability_paths();
|
|
34010
34092
|
CODEX_VENDOR_MARKETPLACES = Object.freeze(["openai-bundled", "openai-curated", "openai-curated-remote"]);
|
|
34011
34093
|
CODEX_REMOTE_VENDOR_MARKETPLACES = Object.freeze(["openai-curated-remote"]);
|
|
34012
|
-
OTHER_PLUGIN_CONTROLS = Object.freeze(
|
|
34094
|
+
OTHER_PLUGIN_CONTROLS = Object.freeze(CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES.filter((entry) => entry !== ".codex-plugin" && entry !== ".app.json"));
|
|
34013
34095
|
VENDOR_MANIFEST_KEYS = Object.freeze(["name", "version", "description", "author", "homepage", "repository", "license", "keywords", "interface", "skills", "apps"]);
|
|
34014
34096
|
DEFAULT_SKILLS_PATHS = Object.freeze(["./skills", "./skills/"]);
|
|
34015
34097
|
});
|
|
@@ -35114,14 +35196,23 @@ function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files,
|
|
|
35114
35196
|
continue;
|
|
35115
35197
|
const parent = join21(cacheRoot, parts[0], parts[1]);
|
|
35116
35198
|
const root = join21(parent, parts[2]);
|
|
35117
|
-
const base = parts[parts.length - 1];
|
|
35118
|
-
if (parts.
|
|
35199
|
+
const base = parts[parts.length - 1], folded = foldCodexPluginEntryName(base);
|
|
35200
|
+
if (parts.length === 3 && (codexPluginRootCapabilityEntry(base) !== null || isCodexSkillDocumentName(base)))
|
|
35201
|
+
refuse3();
|
|
35202
|
+
const rootEntry = parts.length >= 4 ? codexPluginRootCapabilityEntry(parts[3]) : null;
|
|
35203
|
+
if (rootEntry !== null && rootEntry !== parts[3])
|
|
35204
|
+
refuse3();
|
|
35205
|
+
if (rootEntry !== null && !SEMANTIC_BOUND_ROOT_ENTRIES.includes(rootEntry))
|
|
35119
35206
|
refuse3();
|
|
35120
|
-
if (
|
|
35207
|
+
if (isCodexSkillDocumentName(base) && base !== "SKILL.md")
|
|
35121
35208
|
refuse3();
|
|
35122
|
-
if (
|
|
35209
|
+
if (parts.some((part) => CODEX_PLUGIN_MANIFEST_DIRECTORIES.includes(foldCodexPluginEntryName(part))) && (parts.length < 4 || parts[3] !== ".codex-plugin" || (parts.length === 4 ? base !== ".codex-plugin" : parts.length !== 5 || base !== "plugin.json")))
|
|
35123
35210
|
refuse3();
|
|
35124
|
-
if (
|
|
35211
|
+
if ([".app.json", ".mcp.json"].includes(folded) && (parts.length !== 4 || dirname16(member) !== root))
|
|
35212
|
+
refuse3();
|
|
35213
|
+
if ([".app.json", ".mcp.json"].includes(folded) && hookParents.some((reviewed) => reviewed.pluginParent === parent))
|
|
35214
|
+
refuse3();
|
|
35215
|
+
if ((rootEntry === "hooks" || folded === "hooks.json") && (![4, 5].includes(parts.length) || parts[3] !== "hooks" || (parts.length === 4 ? base !== "hooks" : base !== "hooks.json") || !hookParents.some((reviewed) => reviewed.pluginParent === join21(cacheRoot, parts[0], parts[1]))))
|
|
35125
35216
|
refuse3();
|
|
35126
35217
|
}
|
|
35127
35218
|
}
|
|
@@ -35343,13 +35434,15 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
|
|
|
35343
35434
|
if (hash3(priorProjection) !== previous.sha256 || hash3(currentProjection) !== current.sha256 || canonical8(comparable(priorProjection)) !== canonical8(comparable(currentProjection)))
|
|
35344
35435
|
refuse3();
|
|
35345
35436
|
}
|
|
35346
|
-
var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1", identifier4 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value), digest = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), refuse3 = () => {
|
|
35437
|
+
var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1", SEMANTIC_BOUND_ROOT_ENTRIES, identifier4 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value), digest = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), refuse3 = () => {
|
|
35347
35438
|
throw new Error("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED: review Codex plugin cache identity and controls");
|
|
35348
35439
|
}, MAX_DOCUMENT_BYTES, MAX_RECEIPT_BYTES, codexHookEvents;
|
|
35349
35440
|
var init_codex_semantic_cache_witness = __esm(() => {
|
|
35350
35441
|
init_claude_settings_witness();
|
|
35351
35442
|
init_codex_plugin_skill_controls();
|
|
35352
35443
|
init_codex_native_skill_catalog();
|
|
35444
|
+
init_codex_plugin_capability_paths();
|
|
35445
|
+
SEMANTIC_BOUND_ROOT_ENTRIES = Object.freeze([".codex-plugin", ".app.json", ".mcp.json", "hooks"]);
|
|
35353
35446
|
MAX_DOCUMENT_BYTES = 1024 * 1024;
|
|
35354
35447
|
MAX_RECEIPT_BYTES = 16 * 1024;
|
|
35355
35448
|
codexHookEvents = new Set([
|
|
@@ -39028,6 +39121,7 @@ function normalizeRemoteSkill(skill) {
|
|
|
39028
39121
|
if (!name)
|
|
39029
39122
|
throw new Error("Remote skill requires name or slug");
|
|
39030
39123
|
return {
|
|
39124
|
+
...skill.id !== undefined ? { id: skill.id } : {},
|
|
39031
39125
|
name,
|
|
39032
39126
|
displayName: skill.displayName || titleize(name),
|
|
39033
39127
|
description: skill.description || "",
|
|
@@ -39132,11 +39226,12 @@ var init_remote_registry = __esm(() => {
|
|
|
39132
39226
|
details: exports_external.array(exports_external.string()).optional()
|
|
39133
39227
|
}).passthrough();
|
|
39134
39228
|
remoteSkillSchema = exports_external.object({
|
|
39229
|
+
id: exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/).optional(),
|
|
39135
39230
|
name: exports_external.string().min(1).optional(),
|
|
39136
39231
|
slug: exports_external.string().min(1).optional(),
|
|
39137
39232
|
displayName: exports_external.string().optional(),
|
|
39138
39233
|
description: exports_external.string().optional(),
|
|
39139
|
-
category: exports_external.string().optional(),
|
|
39234
|
+
category: exports_external.string().nullable().optional(),
|
|
39140
39235
|
tags: exports_external.array(exports_external.string()).optional(),
|
|
39141
39236
|
dependencies: exports_external.array(exports_external.string()).optional(),
|
|
39142
39237
|
version: exports_external.string().optional(),
|
|
@@ -41525,6 +41620,24 @@ var init_remote_invitation_recovery = __esm(() => {
|
|
|
41525
41620
|
|
|
41526
41621
|
// src/lib/remote-private-publications.ts
|
|
41527
41622
|
import { createHash as createHash26 } from "crypto";
|
|
41623
|
+
function checkedPrivateSkillCreate(value) {
|
|
41624
|
+
const refuse5 = (field3, accepted) => {
|
|
41625
|
+
throw new PrivatePublicationError("INVALID_SKILL_CREATE_INPUT", `Invalid ${field3}. ${accepted}`);
|
|
41626
|
+
};
|
|
41627
|
+
if (!record10(value) || !Object.keys(value).every((key2) => ["slug", "displayName", "description", "visibility", "confirm"].includes(key2)))
|
|
41628
|
+
return refuse5("create input", "Provide only slug, displayName, description, visibility and confirm.");
|
|
41629
|
+
if (value.confirm !== true)
|
|
41630
|
+
throw new PrivatePublicationError("SKILL_CREATE_CONFIRM_REQUIRED", "Explicit confirmation is required to create this skill.");
|
|
41631
|
+
if (typeof value.slug !== "string" || value.slug.length > 128 || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value.slug))
|
|
41632
|
+
return refuse5("slug", "Use lowercase kebab-case, at most 128 characters.");
|
|
41633
|
+
if (typeof value.displayName !== "string" || !value.displayName.trim() || value.displayName.length > 256 || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value.displayName))
|
|
41634
|
+
return refuse5("displayName", "Use nonempty text, at most 256 characters, without control characters.");
|
|
41635
|
+
if (value.description !== undefined && (typeof value.description !== "string" || Buffer.byteLength(value.description) > 8192 || /[\p{Cc}\p{Cs}]/u.test(value.description.replace(/[\r\n\t]/g, ""))))
|
|
41636
|
+
return refuse5("description", "Use text of at most 8192 UTF-8 bytes, without control characters other than tabs and newlines.");
|
|
41637
|
+
if (value.visibility !== undefined && value.visibility !== "private" && value.visibility !== "team")
|
|
41638
|
+
return refuse5("visibility", "Use private or team.");
|
|
41639
|
+
return Object.freeze({ slug: value.slug, displayName: value.displayName.trim(), description: value.description ?? "", visibility: value.visibility ?? "private" });
|
|
41640
|
+
}
|
|
41528
41641
|
function checkedPublicationDeclaration(value) {
|
|
41529
41642
|
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash4(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
41530
41643
|
return bad();
|
|
@@ -41544,11 +41657,11 @@ function checkedPublicationView(value, skillId, intentId, declaration) {
|
|
|
41544
41657
|
return invalid4();
|
|
41545
41658
|
return Object.freeze({ ...value });
|
|
41546
41659
|
}
|
|
41547
|
-
async function boundedJson(url2, init, token, mutation, budget3 = 15000, signal) {
|
|
41660
|
+
async function boundedJson(url2, init, token, mutation, budget3 = 15000, signal, create = false) {
|
|
41548
41661
|
const controller = new AbortController;
|
|
41549
41662
|
let reader;
|
|
41550
41663
|
let response;
|
|
41551
|
-
const timeout2 = new PrivatePublicationError("PUBLICATION_UNCONFIRMED", "No confirmed publication result. Inspect the saved intent before retrying.", mutation);
|
|
41664
|
+
const timeout2 = new PrivatePublicationError(create ? "SKILL_CREATE_UNCONFIRMED" : "PUBLICATION_UNCONFIRMED", create ? "Skill creation could not be confirmed. Inspect the workspace for this slug before another create; do not retry automatically." : "No confirmed publication result. Inspect the saved intent before retrying.", mutation);
|
|
41552
41665
|
let timer;
|
|
41553
41666
|
let abort;
|
|
41554
41667
|
try {
|
|
@@ -41588,11 +41701,19 @@ async function boundedJson(url2, init, token, mutation, budget3 = 15000, signal)
|
|
|
41588
41701
|
return invalid4();
|
|
41589
41702
|
}
|
|
41590
41703
|
if (!response.ok) {
|
|
41591
|
-
const
|
|
41592
|
-
|
|
41593
|
-
|
|
41704
|
+
const known = create ? skillCreateFailures : failures2;
|
|
41705
|
+
const code = record10(body) && typeof body.code === "string" && Object.hasOwn(known, body.code) ? body.code : null;
|
|
41706
|
+
if (code && known[code][0] === response.status)
|
|
41707
|
+
throw new PrivatePublicationError(code, known[code][1], mutation && code === "PUBLICATION_UNCERTAIN", response.status);
|
|
41708
|
+
if (create) {
|
|
41709
|
+
if (response.status >= 500)
|
|
41710
|
+
throw timeout2;
|
|
41711
|
+
throw new PrivatePublicationError("SKILL_CREATE_REQUEST_FAILED", "The server refused skill creation.", false, response.status);
|
|
41712
|
+
}
|
|
41594
41713
|
throw new PrivatePublicationError("PUBLICATION_REQUEST_FAILED", "The publication request was refused. Inspect its status before retrying.", mutation && response.status >= 500, response.status);
|
|
41595
41714
|
}
|
|
41715
|
+
if (create && response.status !== 201)
|
|
41716
|
+
return invalid4();
|
|
41596
41717
|
return body;
|
|
41597
41718
|
})(), new Promise((_, reject) => {
|
|
41598
41719
|
abort = () => {
|
|
@@ -41639,6 +41760,15 @@ class RemotePrivatePublicationsClient {
|
|
|
41639
41760
|
this.membershipId = checked.user.membershipId;
|
|
41640
41761
|
Object.freeze(this);
|
|
41641
41762
|
}
|
|
41763
|
+
async createSkill(input2, options = {}) {
|
|
41764
|
+
const body = checkedPrivateSkillCreate(input2);
|
|
41765
|
+
if (options.timeoutMs !== undefined && (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 1 || options.timeoutMs > 15000))
|
|
41766
|
+
throw new PrivatePublicationError("INVALID_SKILL_CREATE_INPUT", "Invalid timeoutMs. Use an integer from 1 to 15000.");
|
|
41767
|
+
const value = await boundedJson(skillsApiRequestUrl(this.apiOrigin, "/api/v1/skills"), { method: "POST", body: JSON.stringify(body) }, this.#token, true, options.timeoutMs, options.signal, true);
|
|
41768
|
+
if (!record10(value) || !publicationUuid(value.id) || value.slug !== body.slug || value.displayName !== body.displayName || value.description !== body.description || value.visibility !== body.visibility || value.sourceType !== "private_hosted" || !record10(value.metadata) || value.metadata.ownerOrganizationId !== this.organizationId)
|
|
41769
|
+
throw new PrivatePublicationError("SKILL_CREATE_UNCONFIRMED", "Skill creation returned an unbound result. Inspect the workspace for this slug before another create; do not retry automatically.", true);
|
|
41770
|
+
return Object.freeze({ id: value.id, slug: body.slug, visibility: body.visibility, sourceType: "private_hosted", ownerOrganizationId: this.organizationId });
|
|
41771
|
+
}
|
|
41642
41772
|
async getCapability(options = {}) {
|
|
41643
41773
|
if (options.timeoutMs !== undefined && (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 1 || options.timeoutMs > 15000))
|
|
41644
41774
|
return bad();
|
|
@@ -41781,7 +41911,7 @@ class RemotePrivatePublicationsClient {
|
|
|
41781
41911
|
}
|
|
41782
41912
|
}
|
|
41783
41913
|
}
|
|
41784
|
-
var PRIVATE_PUBLICATION_MAX_BYTES, failures2, PrivatePublicationError, bad = () => {
|
|
41914
|
+
var PRIVATE_PUBLICATION_MAX_BYTES, skillCreateFailures, failures2, PrivatePublicationError, bad = () => {
|
|
41785
41915
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
41786
41916
|
}, invalid4 = () => {
|
|
41787
41917
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
@@ -41791,6 +41921,16 @@ var init_remote_private_publications = __esm(() => {
|
|
|
41791
41921
|
init_remote_workspace_selection();
|
|
41792
41922
|
init_skill_contract();
|
|
41793
41923
|
PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
|
|
41924
|
+
skillCreateFailures = {
|
|
41925
|
+
INVALID_SLUG: [400, "Provide a lowercase kebab-case skill slug."],
|
|
41926
|
+
INVALID_DISPLAY_NAME: [400, "Provide a nonempty skill display name."],
|
|
41927
|
+
INVALID_VISIBILITY: [400, "Use private or team visibility for source publication."],
|
|
41928
|
+
SESSION_EXPIRED: [401, "Sign in again before creating a private skill."],
|
|
41929
|
+
INTERACTIVE_SESSION_REQUIRED: [403, "An interactive account session is required to create a private skill."],
|
|
41930
|
+
ACCOUNT_UNAVAILABLE: [403, "The current account membership cannot create a private skill."],
|
|
41931
|
+
PLAN_REQUIRED: [403, "Private and team skills require the Pro plan."],
|
|
41932
|
+
SLUG_CONFLICT: [409, "This skill slug already exists. Inspect the existing skill before publishing."]
|
|
41933
|
+
};
|
|
41794
41934
|
failures2 = {
|
|
41795
41935
|
INVALID_REQUEST: [400, "The publication request is invalid."],
|
|
41796
41936
|
SESSION_EXPIRED: [401, "Sign in again to manage this publication."],
|
|
@@ -48220,15 +48360,42 @@ var init_remote_invitation_tools = __esm(() => {
|
|
|
48220
48360
|
});
|
|
48221
48361
|
|
|
48222
48362
|
// src/lib/private-publication-customer.ts
|
|
48363
|
+
function preparePrivatePublicationSession(requested) {
|
|
48364
|
+
const selectors = [
|
|
48365
|
+
"HASNA_PROFILE",
|
|
48366
|
+
"HASNA_HOME",
|
|
48367
|
+
"HASNA_CONFIG_HOME",
|
|
48368
|
+
"HASNA_STATION",
|
|
48369
|
+
"HASNA_SKILLS_API_URL",
|
|
48370
|
+
"SKILLS_API_URL",
|
|
48371
|
+
"HASNA_SKILLS_API_KEY_OVERRIDE",
|
|
48372
|
+
"HASNA_SKILLS_API_KEY_REF",
|
|
48373
|
+
"HASNA_SKILLS_API_KEY",
|
|
48374
|
+
"SKILLS_API_KEY"
|
|
48375
|
+
];
|
|
48376
|
+
const before = new Map(selectors.map((key2) => [key2, process.env[key2]]));
|
|
48377
|
+
const profile = selectedSkillsProfile(process.env), pending = prepareProfileWorkspace("Manage private publications");
|
|
48378
|
+
const captured = requested ? { ...requested } : undefined;
|
|
48379
|
+
const unchanged3 = () => {
|
|
48380
|
+
if (selectors.some((key2) => process.env[key2] !== before.get(key2)) || selectedSkillsProfile(process.env) !== profile)
|
|
48381
|
+
throw new PrivatePublicationError("PUBLICATION_TARGET_CHANGED", "The selected profile or server changed during verification. Start again with a stable target; no skill action was sent.");
|
|
48382
|
+
};
|
|
48383
|
+
return { origin: pending.origin, async verify(email5, code2) {
|
|
48384
|
+
unchanged3();
|
|
48385
|
+
const target = await pending.resolve();
|
|
48386
|
+
const context2 = captured ?? target.context;
|
|
48387
|
+
if (!context2 || !publicationUuid(context2.userId) || !publicationUuid(context2.membershipId) || target.context && (context2.userId !== target.context.userId || context2.membershipId !== target.context.membershipId))
|
|
48388
|
+
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide the observed user and membership IDs, or select an enrolled workspace profile.");
|
|
48389
|
+
unchanged3();
|
|
48390
|
+
target.unchanged();
|
|
48391
|
+
const client = await new RemoteSkillsAuthClient(target.origin).openPrivatePublications(email5, code2, context2);
|
|
48392
|
+
unchanged3();
|
|
48393
|
+
target.unchanged();
|
|
48394
|
+
return client;
|
|
48395
|
+
} };
|
|
48396
|
+
}
|
|
48223
48397
|
async function privatePublicationSession(email5, code2, requested) {
|
|
48224
|
-
|
|
48225
|
-
const context2 = requested ?? target.context;
|
|
48226
|
-
if (!context2 || !publicationUuid(context2.userId) || !publicationUuid(context2.membershipId) || target.context && (context2.userId !== target.context.userId || context2.membershipId !== target.context.membershipId))
|
|
48227
|
-
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide the observed user and membership IDs, or select an enrolled workspace profile.");
|
|
48228
|
-
target.unchanged();
|
|
48229
|
-
const client = await new RemoteSkillsAuthClient(target.origin).openPrivatePublications(email5, code2, context2);
|
|
48230
|
-
target.unchanged();
|
|
48231
|
-
return client;
|
|
48398
|
+
return preparePrivatePublicationSession(requested).verify(email5, code2);
|
|
48232
48399
|
}
|
|
48233
48400
|
function privatePublicationCustomerError(error61) {
|
|
48234
48401
|
return error61 instanceof PrivatePublicationError ? { error: error61.message, code: error61.code, uncertain: error61.uncertain } : { error: "The publication action could not be confirmed. Preserve the recovery directory and inspect the same intent; credentials were not changed.", code: "PUBLICATION_ACTION_UNCONFIRMED", uncertain: true };
|
|
@@ -48237,6 +48404,7 @@ var init_private_publication_customer = __esm(() => {
|
|
|
48237
48404
|
init_remote_auth();
|
|
48238
48405
|
init_remote_private_publications();
|
|
48239
48406
|
init_workspace_profile();
|
|
48407
|
+
init_instance_credentials();
|
|
48240
48408
|
});
|
|
48241
48409
|
|
|
48242
48410
|
// src/lib/private-publication-recovery.ts
|
package/bin/migrate.js
CHANGED