@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/index.js
CHANGED
|
@@ -36888,7 +36888,7 @@ var package_default;
|
|
|
36888
36888
|
var init_package = __esm(() => {
|
|
36889
36889
|
package_default = {
|
|
36890
36890
|
name: "@hasna/skills",
|
|
36891
|
-
version: "0.10.
|
|
36891
|
+
version: "0.10.78",
|
|
36892
36892
|
description: "Skills library for AI coding agents",
|
|
36893
36893
|
type: "module",
|
|
36894
36894
|
bin: {
|
|
@@ -40398,7 +40398,8 @@ var init_codex_native_compatibility = __esm(() => {
|
|
|
40398
40398
|
"codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40399
40399
|
"codex-cli 0.161.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40400
40400
|
"codex-cli 0.162.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40401
|
-
"codex-cli 0.162.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
40401
|
+
"codex-cli 0.162.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40402
|
+
"codex-cli 0.163.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
40402
40403
|
};
|
|
40403
40404
|
SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
|
|
40404
40405
|
});
|
|
@@ -50455,6 +50456,40 @@ var init_codex_settings_witness_v1 = __esm(() => {
|
|
|
50455
50456
|
VERBOSITY = new Set(["low", "medium", "high"]);
|
|
50456
50457
|
});
|
|
50457
50458
|
|
|
50459
|
+
// src/lib/codex-plugin-capability-paths.ts
|
|
50460
|
+
function foldCodexPluginEntryName(name) {
|
|
50461
|
+
return name.toUpperCase().toLowerCase();
|
|
50462
|
+
}
|
|
50463
|
+
function codexPluginRootCapabilityEntry(name) {
|
|
50464
|
+
const folded = foldCodexPluginEntryName(name);
|
|
50465
|
+
return CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES.includes(folded) ? folded : null;
|
|
50466
|
+
}
|
|
50467
|
+
function isCodexSkillDocumentName(name) {
|
|
50468
|
+
return foldCodexPluginEntryName(name) === "skill.md";
|
|
50469
|
+
}
|
|
50470
|
+
var CODEX_PLUGIN_MANIFEST_LOCATIONS, CODEX_PLUGIN_MANIFEST_DIRECTORIES, CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES;
|
|
50471
|
+
var init_codex_plugin_capability_paths = __esm(() => {
|
|
50472
|
+
CODEX_PLUGIN_MANIFEST_LOCATIONS = Object.freeze([
|
|
50473
|
+
"plugin.json",
|
|
50474
|
+
".codex-plugin/plugin.json",
|
|
50475
|
+
".claude-plugin/plugin.json",
|
|
50476
|
+
".cursor-plugin/plugin.json"
|
|
50477
|
+
]);
|
|
50478
|
+
CODEX_PLUGIN_MANIFEST_DIRECTORIES = Object.freeze([".codex-plugin", ".claude-plugin", ".cursor-plugin"]);
|
|
50479
|
+
CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES = Object.freeze([
|
|
50480
|
+
"plugin.json",
|
|
50481
|
+
".codex-plugin",
|
|
50482
|
+
".claude-plugin",
|
|
50483
|
+
".cursor-plugin",
|
|
50484
|
+
"hooks",
|
|
50485
|
+
"hooks.json",
|
|
50486
|
+
".mcp.json",
|
|
50487
|
+
".app.json",
|
|
50488
|
+
"commands",
|
|
50489
|
+
"agents"
|
|
50490
|
+
]);
|
|
50491
|
+
});
|
|
50492
|
+
|
|
50458
50493
|
// src/lib/codex-hook-mcp-dependencies.ts
|
|
50459
50494
|
import { createHash as createHash13 } from "crypto";
|
|
50460
50495
|
import { basename as basename6, dirname as dirname11, isAbsolute as isAbsolute11, join as join17, resolve as resolve12, sep as sep4 } from "path";
|
|
@@ -50599,15 +50634,13 @@ function captureCodexHookMcpDependencies(configPath, reviewed, configText, chang
|
|
|
50599
50634
|
}
|
|
50600
50635
|
};
|
|
50601
50636
|
const root = join17(cacheRoot, identity3, selectCodexPluginVersion(versions, selectionBudget));
|
|
50602
|
-
const
|
|
50637
|
+
const [agentPluginManifest, ...legacyManifests] = CODEX_PLUGIN_MANIFEST_LOCATIONS;
|
|
50638
|
+
const agent = read2(join17(root, agentPluginManifest));
|
|
50603
50639
|
if (agent !== null) {
|
|
50604
50640
|
const schema = JSON.parse(agent).$schema;
|
|
50605
50641
|
need5(typeof schema !== "string" || !schema.startsWith("https://agent-plugins.org/schemas/"));
|
|
50606
50642
|
}
|
|
50607
|
-
const
|
|
50608
|
-
const claude = read2(join17(root, ".claude-plugin/plugin.json"));
|
|
50609
|
-
const cursor = read2(join17(root, ".cursor-plugin/plugin.json"));
|
|
50610
|
-
const text2 = codex ?? claude ?? cursor;
|
|
50643
|
+
const text2 = legacyManifests.map((location) => read2(join17(root, location))).find((value) => value !== null) ?? null;
|
|
50611
50644
|
if (text2 === null)
|
|
50612
50645
|
continue;
|
|
50613
50646
|
const manifest = JSON.parse(text2);
|
|
@@ -50629,6 +50662,7 @@ var init_codex_hook_mcp_dependencies = __esm(() => {
|
|
|
50629
50662
|
init_claude_settings_witness();
|
|
50630
50663
|
init_agent_discovery_directories();
|
|
50631
50664
|
init_agent_discovery_bytes();
|
|
50665
|
+
init_codex_plugin_capability_paths();
|
|
50632
50666
|
events = new Set(["PreToolUse", "PermissionRequest", "PostToolUse", "PreCompact", "PostCompact", "SessionStart", "SessionEnd", "UserPromptSubmit", "SubagentStart", "SubagentStop", "Stop", "Interrupt"]);
|
|
50633
50667
|
});
|
|
50634
50668
|
|
|
@@ -52942,15 +52976,17 @@ function codexVendorConfigCandidates(text2, cache3, options = {}) {
|
|
|
52942
52976
|
var CODEX_VENDOR_MARKETPLACES, CODEX_REMOTE_VENDOR_MARKETPLACES, identifier3 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value), record4 = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value)), directory = (path) => {
|
|
52943
52977
|
const stat2 = lstatSync14(path, { throwIfNoEntry: false });
|
|
52944
52978
|
return Boolean(stat2?.isDirectory() && !stat2.isSymbolicLink());
|
|
52945
|
-
}, OTHER_PLUGIN_CONTROLS, VENDOR_MANIFEST_KEYS, DEFAULT_SKILLS_PATHS, VENDOR_APP_DECLARATION = "./.app.json", MAX_SUBTREE_ENTRIES = 20000, MAX_SUBTREE_DEPTH = 32, hiddenName = (name) => name.startsWith(".") || name === "node_modules", isSkillDocument
|
|
52979
|
+
}, OTHER_PLUGIN_CONTROLS, VENDOR_MANIFEST_KEYS, DEFAULT_SKILLS_PATHS, VENDOR_APP_DECLARATION = "./.app.json", MAX_SUBTREE_ENTRIES = 20000, MAX_SUBTREE_DEPTH = 32, hiddenName = (name) => name.startsWith(".") || name === "node_modules", isSkillDocument, present = (path) => lstatSync14(path, { throwIfNoEntry: false }) !== undefined, holdsOtherControl = (path) => readdirSync7(path).some((name) => OTHER_PLUGIN_CONTROLS.includes(codexPluginRootCapabilityEntry(name) ?? "")), MAX_TRAILING_VENDOR_ROWS = 16, MAX_VENDOR_TABLES = 8, MAX_CONFIG_CANDIDATES = 128, HEADER;
|
|
52946
52980
|
var init_codex_vendor_refresh = __esm(() => {
|
|
52947
52981
|
init_claude_settings_witness();
|
|
52948
52982
|
init_codex_plugin_skill_controls();
|
|
52983
|
+
init_codex_plugin_capability_paths();
|
|
52949
52984
|
CODEX_VENDOR_MARKETPLACES = Object.freeze(["openai-bundled", "openai-curated", "openai-curated-remote"]);
|
|
52950
52985
|
CODEX_REMOTE_VENDOR_MARKETPLACES = Object.freeze(["openai-curated-remote"]);
|
|
52951
|
-
OTHER_PLUGIN_CONTROLS = Object.freeze(
|
|
52986
|
+
OTHER_PLUGIN_CONTROLS = Object.freeze(CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES.filter((entry) => entry !== ".codex-plugin" && entry !== ".app.json"));
|
|
52952
52987
|
VENDOR_MANIFEST_KEYS = Object.freeze(["name", "version", "description", "author", "homepage", "repository", "license", "keywords", "interface", "skills", "apps"]);
|
|
52953
52988
|
DEFAULT_SKILLS_PATHS = Object.freeze(["./skills", "./skills/"]);
|
|
52989
|
+
isSkillDocument = isCodexSkillDocumentName;
|
|
52954
52990
|
HEADER = /^[ \t]*(\[\[|\[)[ \t]*([^[\]\r\n]+?)[ \t]*(\]\]|\])[ \t]*(?:#[^\r\n]*)?\r?\n?$/;
|
|
52955
52991
|
});
|
|
52956
52992
|
|
|
@@ -54056,6 +54092,10 @@ function skillsFileHasCredential(file) {
|
|
|
54056
54092
|
return false;
|
|
54057
54093
|
return /^\s*(?:export\s+)?(?:HASNA_SKILLS_API_KEY|SKILLS_API_KEY|HASNA_SKILLS_API_KEY_REF)\s*=\s*\S/m.test(text2);
|
|
54058
54094
|
}
|
|
54095
|
+
function skillsFileHasVaultReference(file) {
|
|
54096
|
+
const text2 = readMetadataText(file);
|
|
54097
|
+
return text2 !== null && /^\s*(?:export\s+)?HASNA_SKILLS_API_KEY_REF\s*=\s*\S/m.test(text2);
|
|
54098
|
+
}
|
|
54059
54099
|
var SKILLS_BOUND_API_URL = "HASNA_SKILLS_BOUND_API_URL";
|
|
54060
54100
|
var init_instance_credentials = __esm(() => {
|
|
54061
54101
|
init_transport();
|
|
@@ -54090,6 +54130,25 @@ var init_local_opt_in = __esm(() => {
|
|
|
54090
54130
|
// src/lib/product-default.ts
|
|
54091
54131
|
var SKILLS_PRODUCT_DEFAULT_ORIGIN = "https://skills.md";
|
|
54092
54132
|
|
|
54133
|
+
// src/lib/credential-profile-command.ts
|
|
54134
|
+
function skillsShellArgument(value) {
|
|
54135
|
+
return /^[A-Za-z0-9._:/-]+$/.test(value) ? value : `'${value.replace(/'/g, "'\\''")}'`;
|
|
54136
|
+
}
|
|
54137
|
+
function skillsApiUrlEnvironment(origin) {
|
|
54138
|
+
return urlKeys.map((name) => `${name}=${skillsShellArgument(origin)}`).join(" ");
|
|
54139
|
+
}
|
|
54140
|
+
function skillsProfileCommand(command, env3 = process.env, origin) {
|
|
54141
|
+
const profile = selectedSkillsProfile(env3);
|
|
54142
|
+
const prefix = origin && urlKeys.some((name) => env3[name]?.trim()) ? `${skillsApiUrlEnvironment(origin)} ` : "";
|
|
54143
|
+
return `${prefix}skills${profile ? ` --profile ${profile}` : ""} ${command}`;
|
|
54144
|
+
}
|
|
54145
|
+
var urlKeys;
|
|
54146
|
+
var init_credential_profile_command = __esm(() => {
|
|
54147
|
+
init_instance_credentials();
|
|
54148
|
+
init_transport();
|
|
54149
|
+
urlKeys = clientTransportEnvKeys("skills").apiUrlKeys;
|
|
54150
|
+
});
|
|
54151
|
+
|
|
54093
54152
|
// src/lib/fleet-credentials.ts
|
|
54094
54153
|
var exports_fleet_credentials = {};
|
|
54095
54154
|
__export(exports_fleet_credentials, {
|
|
@@ -54114,6 +54173,8 @@ __export(exports_fleet_credentials, {
|
|
|
54114
54173
|
gatewaySignInRefusal: () => gatewaySignInRefusal,
|
|
54115
54174
|
credentialPairing: () => credentialPairing,
|
|
54116
54175
|
configuredSkillsApiUrl: () => configuredSkillsApiUrl,
|
|
54176
|
+
captureSkillsSignInTarget: () => captureSkillsSignInTarget,
|
|
54177
|
+
assertSkillsSignInCredentialReplaceable: () => assertSkillsSignInCredentialReplaceable,
|
|
54117
54178
|
SkillsFleetCredentialError: () => SkillsFleetCredentialError,
|
|
54118
54179
|
SKILLS_LOCAL_OPT_IN_ENV_KEYS: () => SKILLS_LOCAL_OPT_IN_ENV_KEYS,
|
|
54119
54180
|
SKILLS_CREDENTIAL_TIERS: () => SKILLS_CREDENTIAL_TIERS,
|
|
@@ -54419,8 +54480,24 @@ function gatewaySignInRefusal(target) {
|
|
|
54419
54480
|
if (normalizeSkillsApiOrigin(target.origin) !== normalizeSkillsApiOrigin(defaultFleetGatewayBaseUrl(SKILLS_APP)))
|
|
54420
54481
|
return null;
|
|
54421
54482
|
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`;
|
|
54422
|
-
const
|
|
54423
|
-
return new SkillsFleetCredentialError(`${cause}, which has no sign-in service. Nothing was sent
|
|
54483
|
+
const command = (SKILLS_API_URL_ENV_KEYS.includes(target.source) ? `${skillsApiUrlEnvironment(SKILLS_PRODUCT_DEFAULT_ORIGIN)} ` : "") + "skills --profile <new-profile> login";
|
|
54484
|
+
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]);
|
|
54485
|
+
}
|
|
54486
|
+
function assertSkillsSignInCredentialReplaceable(env3 = process.env, profile) {
|
|
54487
|
+
const files = skillsProfileCredentialFiles(env3, profile);
|
|
54488
|
+
const verifyUnchanged = captureSkillsCredentialFiles(files);
|
|
54489
|
+
const gateway = normalizeSkillsApiOrigin(defaultFleetGatewayBaseUrl(SKILLS_APP));
|
|
54490
|
+
const command = (SKILLS_API_URL_ENV_KEYS.some((name) => env3[name]?.trim()) ? `${skillsApiUrlEnvironment(SKILLS_PRODUCT_DEFAULT_ORIGIN)} ` : "") + "skills --profile <new-profile> login";
|
|
54491
|
+
for (const file of files) {
|
|
54492
|
+
if (!skillsFileHasCredential(file))
|
|
54493
|
+
continue;
|
|
54494
|
+
const metadata = readSkillsInstanceMetadata(file);
|
|
54495
|
+
const instance = metadata.binding ?? metadata.apiUrl;
|
|
54496
|
+
if (skillsFileHasVaultReference(file) || !instance || normalizeSkillsApiOrigin(instance) === gateway) {
|
|
54497
|
+
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]);
|
|
54498
|
+
}
|
|
54499
|
+
}
|
|
54500
|
+
verifyUnchanged();
|
|
54424
54501
|
}
|
|
54425
54502
|
function explicitSignInOrigin(url) {
|
|
54426
54503
|
if (!url.trim() || /[\x00-\x1f\x7f]/.test(url)) {
|
|
@@ -54448,13 +54525,15 @@ function resolveSkillsSignInOrigin(env3 = process.env, options = {}, explicitUrl
|
|
|
54448
54525
|
const snapshot = snapshotSkillsEnvironment(env3);
|
|
54449
54526
|
const resolvedOptions = snapshotSkillsOptions(env3, options);
|
|
54450
54527
|
const profile = resolvedOptions.credentials?.profile;
|
|
54528
|
+
assertSkillsSignInCredentialReplaceable(snapshot, profile);
|
|
54451
54529
|
const configured = configuredSkillsApiUrl(snapshot, resolvedOptions.credentials?.keychain, profile);
|
|
54452
54530
|
const declared = configured && configured.source !== "default" ? configured : null;
|
|
54453
54531
|
if (explicitUrl !== undefined) {
|
|
54454
54532
|
const origin = explicitSignInOrigin(explicitUrl);
|
|
54455
54533
|
const storedHere = declared ? skillsProfileCredentialFiles(snapshot, profile).includes(declared.source) : false;
|
|
54456
54534
|
if (declared && !storedHere && normalizeSkillsApiOrigin(declared.value) !== origin) {
|
|
54457
|
-
|
|
54535
|
+
const command = `${skillsApiUrlEnvironment(origin)} skills --profile <new-profile> login`;
|
|
54536
|
+
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]);
|
|
54458
54537
|
}
|
|
54459
54538
|
return { origin, source: "--url" };
|
|
54460
54539
|
}
|
|
@@ -54486,6 +54565,14 @@ function resolveSkillsSignInOrigin(env3 = process.env, options = {}, explicitUrl
|
|
|
54486
54565
|
throw error;
|
|
54487
54566
|
}
|
|
54488
54567
|
}
|
|
54568
|
+
function captureSkillsSignInTarget(env3 = process.env, options = {}, explicitUrl) {
|
|
54569
|
+
const snapshot = snapshotSkillsEnvironment(env3);
|
|
54570
|
+
const profile = options.credentials?.profile ?? selectedCliSkillsCredentialProfile();
|
|
54571
|
+
const unchanged2 = captureSkillsCredentialFiles(skillsProfileCredentialFiles(snapshot, profile));
|
|
54572
|
+
const target = resolveSkillsSignInOrigin(env3, options, explicitUrl);
|
|
54573
|
+
unchanged2();
|
|
54574
|
+
return { ...target, unchanged: unchanged2 };
|
|
54575
|
+
}
|
|
54489
54576
|
function requireSkillsFleet(action = "This command", env3 = process.env, options = {}) {
|
|
54490
54577
|
const fleet = resolveSkillsFleet(env3, options);
|
|
54491
54578
|
if (fleet.mode === "hosted")
|
|
@@ -54497,6 +54584,7 @@ var init_fleet_credentials = __esm(() => {
|
|
|
54497
54584
|
init_transport();
|
|
54498
54585
|
init_instance_credentials();
|
|
54499
54586
|
init_local_opt_in();
|
|
54587
|
+
init_credential_profile_command();
|
|
54500
54588
|
init_local_opt_in();
|
|
54501
54589
|
ENV_KEYS = clientTransportEnvKeys(SKILLS_APP);
|
|
54502
54590
|
SKILLS_API_URL_ENV_KEYS = ENV_KEYS.apiUrlKeys;
|
|
@@ -56074,14 +56162,23 @@ function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files,
|
|
|
56074
56162
|
continue;
|
|
56075
56163
|
const parent = join28(cacheRoot, parts[0], parts[1]);
|
|
56076
56164
|
const root = join28(parent, parts[2]);
|
|
56077
|
-
const base2 = parts[parts.length - 1];
|
|
56078
|
-
if (parts.
|
|
56165
|
+
const base2 = parts[parts.length - 1], folded = foldCodexPluginEntryName(base2);
|
|
56166
|
+
if (parts.length === 3 && (codexPluginRootCapabilityEntry(base2) !== null || isCodexSkillDocumentName(base2)))
|
|
56167
|
+
refuse4();
|
|
56168
|
+
const rootEntry = parts.length >= 4 ? codexPluginRootCapabilityEntry(parts[3]) : null;
|
|
56169
|
+
if (rootEntry !== null && rootEntry !== parts[3])
|
|
56170
|
+
refuse4();
|
|
56171
|
+
if (rootEntry !== null && !SEMANTIC_BOUND_ROOT_ENTRIES.includes(rootEntry))
|
|
56079
56172
|
refuse4();
|
|
56080
|
-
if (
|
|
56173
|
+
if (isCodexSkillDocumentName(base2) && base2 !== "SKILL.md")
|
|
56081
56174
|
refuse4();
|
|
56082
|
-
if (
|
|
56175
|
+
if (parts.some((part) => CODEX_PLUGIN_MANIFEST_DIRECTORIES.includes(foldCodexPluginEntryName(part))) && (parts.length < 4 || parts[3] !== ".codex-plugin" || (parts.length === 4 ? base2 !== ".codex-plugin" : parts.length !== 5 || base2 !== "plugin.json")))
|
|
56083
56176
|
refuse4();
|
|
56084
|
-
if (
|
|
56177
|
+
if ([".app.json", ".mcp.json"].includes(folded) && (parts.length !== 4 || dirname18(member) !== root))
|
|
56178
|
+
refuse4();
|
|
56179
|
+
if ([".app.json", ".mcp.json"].includes(folded) && hookParents.some((reviewed) => reviewed.pluginParent === parent))
|
|
56180
|
+
refuse4();
|
|
56181
|
+
if ((rootEntry === "hooks" || folded === "hooks.json") && (![4, 5].includes(parts.length) || parts[3] !== "hooks" || (parts.length === 4 ? base2 !== "hooks" : base2 !== "hooks.json") || !hookParents.some((reviewed) => reviewed.pluginParent === join28(cacheRoot, parts[0], parts[1]))))
|
|
56085
56182
|
refuse4();
|
|
56086
56183
|
}
|
|
56087
56184
|
}
|
|
@@ -56303,13 +56400,15 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
|
|
|
56303
56400
|
if (hash2(priorProjection) !== previous.sha256 || hash2(currentProjection) !== current.sha256 || canonical8(comparable(priorProjection)) !== canonical8(comparable(currentProjection)))
|
|
56304
56401
|
refuse4();
|
|
56305
56402
|
}
|
|
56306
|
-
var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1", identifier5 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value), digest = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), refuse4 = () => {
|
|
56403
|
+
var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1", SEMANTIC_BOUND_ROOT_ENTRIES, identifier5 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value), digest = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), refuse4 = () => {
|
|
56307
56404
|
throw new Error("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED: review Codex plugin cache identity and controls");
|
|
56308
56405
|
}, MAX_DOCUMENT_BYTES, MAX_RECEIPT_BYTES, codexHookEvents;
|
|
56309
56406
|
var init_codex_semantic_cache_witness = __esm(() => {
|
|
56310
56407
|
init_claude_settings_witness();
|
|
56311
56408
|
init_codex_plugin_skill_controls();
|
|
56312
56409
|
init_codex_native_skill_catalog();
|
|
56410
|
+
init_codex_plugin_capability_paths();
|
|
56411
|
+
SEMANTIC_BOUND_ROOT_ENTRIES = Object.freeze([".codex-plugin", ".app.json", ".mcp.json", "hooks"]);
|
|
56313
56412
|
MAX_DOCUMENT_BYTES = 1024 * 1024;
|
|
56314
56413
|
MAX_RECEIPT_BYTES = 16 * 1024;
|
|
56315
56414
|
codexHookEvents = new Set([
|
|
@@ -66250,7 +66349,8 @@ function getAuthConfig(env3 = process.env, options = {}) {
|
|
|
66250
66349
|
return null;
|
|
66251
66350
|
return { apiKey: fleet.apiKey, ...readIdentity(env3) };
|
|
66252
66351
|
}
|
|
66253
|
-
function writeCredentialValues(values2, env3 = process.env) {
|
|
66352
|
+
function writeCredentialValues(values2, env3 = process.env, beforeWrite) {
|
|
66353
|
+
beforeWrite?.();
|
|
66254
66354
|
const file = skillsCredentialFilePath(env3);
|
|
66255
66355
|
mkdirSync14(dirname29(file), { recursive: true, mode: 448 });
|
|
66256
66356
|
const lines = [];
|
|
@@ -66279,9 +66379,16 @@ function writeCredentialValues(values2, env3 = process.env) {
|
|
|
66279
66379
|
`) + `
|
|
66280
66380
|
`;
|
|
66281
66381
|
const temp = `${file}.tmp-${process.pid}`;
|
|
66282
|
-
writeFileSync11(temp, body, { mode: 384 });
|
|
66283
|
-
|
|
66284
|
-
|
|
66382
|
+
writeFileSync11(temp, body, { mode: 384, flag: "wx" });
|
|
66383
|
+
try {
|
|
66384
|
+
chmodSync2(temp, 384);
|
|
66385
|
+
beforeWrite?.();
|
|
66386
|
+
renameSync8(temp, file);
|
|
66387
|
+
} finally {
|
|
66388
|
+
try {
|
|
66389
|
+
unlinkSync6(temp);
|
|
66390
|
+
} catch {}
|
|
66391
|
+
}
|
|
66285
66392
|
return file;
|
|
66286
66393
|
}
|
|
66287
66394
|
function readCredentialValue(key2, env3 = process.env) {
|
|
@@ -66325,7 +66432,14 @@ function safeOrigin(url) {
|
|
|
66325
66432
|
return null;
|
|
66326
66433
|
}
|
|
66327
66434
|
}
|
|
66328
|
-
function saveAuthConfig(config, env3 = process.env, authenticatedOrigin, issuedBy) {
|
|
66435
|
+
function saveAuthConfig(config, env3 = process.env, authenticatedOrigin, issuedBy, assertUnchanged) {
|
|
66436
|
+
const unchanged3 = assertUnchanged ?? captureSkillsCredentialFiles(skillsProfileCredentialFiles(env3));
|
|
66437
|
+
const beforeWrite = () => {
|
|
66438
|
+
unchanged3();
|
|
66439
|
+
if (issuedBy)
|
|
66440
|
+
assertSkillsSignInCredentialReplaceable(env3);
|
|
66441
|
+
};
|
|
66442
|
+
beforeWrite();
|
|
66329
66443
|
const apiKey = config.apiKey.trim();
|
|
66330
66444
|
if (!apiKey)
|
|
66331
66445
|
throw new Error("Refusing to store an empty Skills API key.");
|
|
@@ -66337,7 +66451,7 @@ function saveAuthConfig(config, env3 = process.env, authenticatedOrigin, issuedB
|
|
|
66337
66451
|
const previous = readIdentityRecord(env3);
|
|
66338
66452
|
const loginWroteBefore = previous?.urlWrittenBy === "login" && typeof previous.apiUrl === "string" && safeOrigin(previous.apiUrl) === apiUrl;
|
|
66339
66453
|
const urlWrittenByLogin = issuedBy !== undefined && (!previousUrl || safeOrigin(previousUrl) !== apiUrl || loginWroteBefore);
|
|
66340
|
-
const file = writeCredentialValues({ SKILLS_API_KEY: null, SKILLS_API_URL: null, [SKILLS_API_KEY_REF]: null, [SKILLS_API_KEY_ENV]: apiKey, [SKILLS_BOUND_API_URL]: apiUrl, [SKILLS_API_URL_ENV]: apiUrl }, env3);
|
|
66454
|
+
const file = writeCredentialValues({ SKILLS_API_KEY: null, SKILLS_API_URL: null, [SKILLS_API_KEY_REF]: null, [SKILLS_API_KEY_ENV]: apiKey, [SKILLS_BOUND_API_URL]: apiUrl, [SKILLS_API_URL_ENV]: apiUrl }, env3, beforeWrite);
|
|
66341
66455
|
const identity6 = {};
|
|
66342
66456
|
for (const field3 of ["email", "orgId", "orgSlug", "userId"]) {
|
|
66343
66457
|
const value = config[field3];
|
|
@@ -66633,6 +66747,24 @@ var init_remote_workspace_selection = __esm(() => {
|
|
|
66633
66747
|
|
|
66634
66748
|
// src/lib/remote-private-publications.ts
|
|
66635
66749
|
import { createHash as createHash30 } from "crypto";
|
|
66750
|
+
function checkedPrivateSkillCreate(value) {
|
|
66751
|
+
const refuse6 = (field3, accepted) => {
|
|
66752
|
+
throw new PrivatePublicationError("INVALID_SKILL_CREATE_INPUT", `Invalid ${field3}. ${accepted}`);
|
|
66753
|
+
};
|
|
66754
|
+
if (!record7(value) || !Object.keys(value).every((key2) => ["slug", "displayName", "description", "visibility", "confirm"].includes(key2)))
|
|
66755
|
+
return refuse6("create input", "Provide only slug, displayName, description, visibility and confirm.");
|
|
66756
|
+
if (value.confirm !== true)
|
|
66757
|
+
throw new PrivatePublicationError("SKILL_CREATE_CONFIRM_REQUIRED", "Explicit confirmation is required to create this skill.");
|
|
66758
|
+
if (typeof value.slug !== "string" || value.slug.length > 128 || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value.slug))
|
|
66759
|
+
return refuse6("slug", "Use lowercase kebab-case, at most 128 characters.");
|
|
66760
|
+
if (typeof value.displayName !== "string" || !value.displayName.trim() || value.displayName.length > 256 || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value.displayName))
|
|
66761
|
+
return refuse6("displayName", "Use nonempty text, at most 256 characters, without control characters.");
|
|
66762
|
+
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, ""))))
|
|
66763
|
+
return refuse6("description", "Use text of at most 8192 UTF-8 bytes, without control characters other than tabs and newlines.");
|
|
66764
|
+
if (value.visibility !== undefined && value.visibility !== "private" && value.visibility !== "team")
|
|
66765
|
+
return refuse6("visibility", "Use private or team.");
|
|
66766
|
+
return Object.freeze({ slug: value.slug, displayName: value.displayName.trim(), description: value.description ?? "", visibility: value.visibility ?? "private" });
|
|
66767
|
+
}
|
|
66636
66768
|
function checkedPublicationDeclaration(value) {
|
|
66637
66769
|
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)
|
|
66638
66770
|
return bad();
|
|
@@ -66652,11 +66784,11 @@ function checkedPublicationView(value, skillId, intentId, declaration) {
|
|
|
66652
66784
|
return invalid3();
|
|
66653
66785
|
return Object.freeze({ ...value });
|
|
66654
66786
|
}
|
|
66655
|
-
async function boundedJson(url, init, token, mutation, budget2 = 15000, signal) {
|
|
66787
|
+
async function boundedJson(url, init, token, mutation, budget2 = 15000, signal, create3 = false) {
|
|
66656
66788
|
const controller = new AbortController;
|
|
66657
66789
|
let reader;
|
|
66658
66790
|
let response;
|
|
66659
|
-
const timeout = new PrivatePublicationError("PUBLICATION_UNCONFIRMED", "No confirmed publication result. Inspect the saved intent before retrying.", mutation);
|
|
66791
|
+
const timeout = new PrivatePublicationError(create3 ? "SKILL_CREATE_UNCONFIRMED" : "PUBLICATION_UNCONFIRMED", create3 ? "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);
|
|
66660
66792
|
let timer;
|
|
66661
66793
|
let abort;
|
|
66662
66794
|
try {
|
|
@@ -66696,11 +66828,19 @@ async function boundedJson(url, init, token, mutation, budget2 = 15000, signal)
|
|
|
66696
66828
|
return invalid3();
|
|
66697
66829
|
}
|
|
66698
66830
|
if (!response.ok) {
|
|
66699
|
-
const
|
|
66700
|
-
|
|
66701
|
-
|
|
66831
|
+
const known = create3 ? skillCreateFailures : failures;
|
|
66832
|
+
const code = record7(body) && typeof body.code === "string" && Object.hasOwn(known, body.code) ? body.code : null;
|
|
66833
|
+
if (code && known[code][0] === response.status)
|
|
66834
|
+
throw new PrivatePublicationError(code, known[code][1], mutation && code === "PUBLICATION_UNCERTAIN", response.status);
|
|
66835
|
+
if (create3) {
|
|
66836
|
+
if (response.status >= 500)
|
|
66837
|
+
throw timeout;
|
|
66838
|
+
throw new PrivatePublicationError("SKILL_CREATE_REQUEST_FAILED", "The server refused skill creation.", false, response.status);
|
|
66839
|
+
}
|
|
66702
66840
|
throw new PrivatePublicationError("PUBLICATION_REQUEST_FAILED", "The publication request was refused. Inspect its status before retrying.", mutation && response.status >= 500, response.status);
|
|
66703
66841
|
}
|
|
66842
|
+
if (create3 && response.status !== 201)
|
|
66843
|
+
return invalid3();
|
|
66704
66844
|
return body;
|
|
66705
66845
|
})(), new Promise((_, reject2) => {
|
|
66706
66846
|
abort = () => {
|
|
@@ -66747,6 +66887,15 @@ class RemotePrivatePublicationsClient {
|
|
|
66747
66887
|
this.membershipId = checked.user.membershipId;
|
|
66748
66888
|
Object.freeze(this);
|
|
66749
66889
|
}
|
|
66890
|
+
async createSkill(input, options = {}) {
|
|
66891
|
+
const body = checkedPrivateSkillCreate(input);
|
|
66892
|
+
if (options.timeoutMs !== undefined && (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 1 || options.timeoutMs > 15000))
|
|
66893
|
+
throw new PrivatePublicationError("INVALID_SKILL_CREATE_INPUT", "Invalid timeoutMs. Use an integer from 1 to 15000.");
|
|
66894
|
+
const value = await boundedJson(skillsApiRequestUrl(this.apiOrigin, "/api/v1/skills"), { method: "POST", body: JSON.stringify(body) }, this.#token, true, options.timeoutMs, options.signal, true);
|
|
66895
|
+
if (!record7(value) || !publicationUuid(value.id) || value.slug !== body.slug || value.displayName !== body.displayName || value.description !== body.description || value.visibility !== body.visibility || value.sourceType !== "private_hosted" || !record7(value.metadata) || value.metadata.ownerOrganizationId !== this.organizationId)
|
|
66896
|
+
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);
|
|
66897
|
+
return Object.freeze({ id: value.id, slug: body.slug, visibility: body.visibility, sourceType: "private_hosted", ownerOrganizationId: this.organizationId });
|
|
66898
|
+
}
|
|
66750
66899
|
async getCapability(options = {}) {
|
|
66751
66900
|
if (options.timeoutMs !== undefined && (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 1 || options.timeoutMs > 15000))
|
|
66752
66901
|
return bad();
|
|
@@ -66889,7 +67038,7 @@ class RemotePrivatePublicationsClient {
|
|
|
66889
67038
|
}
|
|
66890
67039
|
}
|
|
66891
67040
|
}
|
|
66892
|
-
var PRIVATE_PUBLICATION_MAX_BYTES, failures, PrivatePublicationError, bad = () => {
|
|
67041
|
+
var PRIVATE_PUBLICATION_MAX_BYTES, skillCreateFailures, failures, PrivatePublicationError, bad = () => {
|
|
66893
67042
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
66894
67043
|
}, invalid3 = () => {
|
|
66895
67044
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
@@ -66899,6 +67048,16 @@ var init_remote_private_publications = __esm(() => {
|
|
|
66899
67048
|
init_remote_workspace_selection();
|
|
66900
67049
|
init_skill_contract();
|
|
66901
67050
|
PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
|
|
67051
|
+
skillCreateFailures = {
|
|
67052
|
+
INVALID_SLUG: [400, "Provide a lowercase kebab-case skill slug."],
|
|
67053
|
+
INVALID_DISPLAY_NAME: [400, "Provide a nonempty skill display name."],
|
|
67054
|
+
INVALID_VISIBILITY: [400, "Use private or team visibility for source publication."],
|
|
67055
|
+
SESSION_EXPIRED: [401, "Sign in again before creating a private skill."],
|
|
67056
|
+
INTERACTIVE_SESSION_REQUIRED: [403, "An interactive account session is required to create a private skill."],
|
|
67057
|
+
ACCOUNT_UNAVAILABLE: [403, "The current account membership cannot create a private skill."],
|
|
67058
|
+
PLAN_REQUIRED: [403, "Private and team skills require the Pro plan."],
|
|
67059
|
+
SLUG_CONFLICT: [409, "This skill slug already exists. Inspect the existing skill before publishing."]
|
|
67060
|
+
};
|
|
66902
67061
|
failures = {
|
|
66903
67062
|
INVALID_REQUEST: [400, "The publication request is invalid."],
|
|
66904
67063
|
SESSION_EXPIRED: [401, "Sign in again to manage this publication."],
|
|
@@ -88497,7 +88656,10 @@ function clearPendingDeviceSignIn(env3 = process.env, origin) {
|
|
|
88497
88656
|
}
|
|
88498
88657
|
}
|
|
88499
88658
|
}
|
|
88500
|
-
async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "sign-in") {
|
|
88659
|
+
async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "sign-in", assertUnchanged) {
|
|
88660
|
+
const unchanged3 = assertUnchanged ?? captureSkillsCredentialFiles(skillsProfileCredentialFiles(env3));
|
|
88661
|
+
unchanged3();
|
|
88662
|
+
assertSkillsSignInCredentialReplaceable(env3);
|
|
88501
88663
|
let apiKey = typeof result2.apiKey === "string" && result2.apiKey.trim() ? result2.apiKey : undefined;
|
|
88502
88664
|
if (!apiKey && typeof result2.token === "string" && result2.token) {
|
|
88503
88665
|
const created = await new RemoteSkillsAuthClient(origin).request("/api/auth/keys", {
|
|
@@ -88515,7 +88677,7 @@ async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "si
|
|
|
88515
88677
|
...boundedText(result2.organization?.id) ? { orgId: result2.organization.id } : {},
|
|
88516
88678
|
...boundedText(result2.organization?.slug) ? { orgSlug: result2.organization.slug } : {},
|
|
88517
88679
|
...boundedText(result2.user?.id) ? { userId: result2.user.id } : {}
|
|
88518
|
-
}, env3, origin, issuedBy);
|
|
88680
|
+
}, env3, origin, issuedBy, unchanged3);
|
|
88519
88681
|
}
|
|
88520
88682
|
function manualRevocationHint(origin) {
|
|
88521
88683
|
if (origin === SKILLS_PRODUCT_DEFAULT_ORIGIN) {
|
|
@@ -88881,6 +89043,7 @@ function normalizeRemoteSkill(skill) {
|
|
|
88881
89043
|
if (!name)
|
|
88882
89044
|
throw new Error("Remote skill requires name or slug");
|
|
88883
89045
|
return {
|
|
89046
|
+
...skill.id !== undefined ? { id: skill.id } : {},
|
|
88884
89047
|
name,
|
|
88885
89048
|
displayName: skill.displayName || titleize(name),
|
|
88886
89049
|
description: skill.description || "",
|
|
@@ -88999,11 +89162,12 @@ var init_remote_registry = __esm(() => {
|
|
|
88999
89162
|
details: exports_external.array(exports_external.string()).optional()
|
|
89000
89163
|
}).passthrough();
|
|
89001
89164
|
remoteSkillSchema = exports_external.object({
|
|
89165
|
+
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(),
|
|
89002
89166
|
name: exports_external.string().min(1).optional(),
|
|
89003
89167
|
slug: exports_external.string().min(1).optional(),
|
|
89004
89168
|
displayName: exports_external.string().optional(),
|
|
89005
89169
|
description: exports_external.string().optional(),
|
|
89006
|
-
category: exports_external.string().optional(),
|
|
89170
|
+
category: exports_external.string().nullable().optional(),
|
|
89007
89171
|
tags: exports_external.array(exports_external.string()).optional(),
|
|
89008
89172
|
dependencies: exports_external.array(exports_external.string()).optional(),
|
|
89009
89173
|
version: exports_external.string().optional(),
|
|
@@ -99452,6 +99616,43 @@ var init_run_state = __esm(() => {
|
|
|
99452
99616
|
init_project_state();
|
|
99453
99617
|
});
|
|
99454
99618
|
|
|
99619
|
+
// src/lib/mcp-registration-environment.ts
|
|
99620
|
+
import { isAbsolute as isAbsolute33 } from "path";
|
|
99621
|
+
function skillsMcpRegistrationEnvironment(env3 = process.env, origin) {
|
|
99622
|
+
const result2 = {};
|
|
99623
|
+
const profile = selectedSkillsProfile(env3);
|
|
99624
|
+
if (profile)
|
|
99625
|
+
result2[CREDENTIAL_PROFILE_ENV_KEY] = profile;
|
|
99626
|
+
for (const key2 of ["HASNA_HOME", "HASNA_CONFIG_HOME"]) {
|
|
99627
|
+
const value = env3[key2];
|
|
99628
|
+
if (value === undefined)
|
|
99629
|
+
continue;
|
|
99630
|
+
if (!isAbsolute33(value) || /[\x00-\x1f\x7f]/.test(value))
|
|
99631
|
+
throw new Error(`Invalid ${key2}; expected an absolute configuration path`);
|
|
99632
|
+
result2[key2] = value;
|
|
99633
|
+
}
|
|
99634
|
+
if (origin !== undefined || urlKeys2.some((key2) => env3[key2] !== undefined)) {
|
|
99635
|
+
try {
|
|
99636
|
+
const source = origin === undefined ? env3 : { ...env3, ...Object.fromEntries(urlKeys2.map((key2) => [key2, origin])) };
|
|
99637
|
+
const configured = configuredSkillsApiUrl(source);
|
|
99638
|
+
if (!configured)
|
|
99639
|
+
throw new Error;
|
|
99640
|
+
for (const key2 of urlKeys2)
|
|
99641
|
+
result2[key2] = configured.value;
|
|
99642
|
+
} catch {
|
|
99643
|
+
throw new Error("Invalid Skills MCP API URL; expected matching HTTPS or loopback HTTP origins without credentials, query or fragment");
|
|
99644
|
+
}
|
|
99645
|
+
}
|
|
99646
|
+
return Object.freeze(result2);
|
|
99647
|
+
}
|
|
99648
|
+
var urlKeys2;
|
|
99649
|
+
var init_mcp_registration_environment = __esm(() => {
|
|
99650
|
+
init_transport();
|
|
99651
|
+
init_instance_credentials();
|
|
99652
|
+
init_fleet_credentials();
|
|
99653
|
+
urlKeys2 = clientTransportEnvKeys("skills").apiUrlKeys;
|
|
99654
|
+
});
|
|
99655
|
+
|
|
99455
99656
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
99456
99657
|
function assertCompleteRequestPrompt(request2) {
|
|
99457
99658
|
if (request2.params.ref.type !== "ref/prompt") {
|
|
@@ -111493,6 +111694,7 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
111493
111694
|
const env3 = { ...source }, profile = selectedSkillsProfile(env3);
|
|
111494
111695
|
if (!profile)
|
|
111495
111696
|
return fail4("Workspace login requires an explicit HASNA_PROFILE name.");
|
|
111697
|
+
assertSkillsSignInCredentialReplaceable(env3);
|
|
111496
111698
|
if (["HASNA_SKILLS_API_KEY_OVERRIDE", "HASNA_SKILLS_API_KEY_REF", "HASNA_SKILLS_API_KEY", "SKILLS_API_KEY"].some((name) => env3[name]?.trim()))
|
|
111497
111699
|
return fail4("Clear injected API keys before enrolling a named workspace profile.");
|
|
111498
111700
|
const origin = getApiUrl("Sign in to a workspace", env3);
|
|
@@ -111789,7 +111991,7 @@ var init_recurring_customer = __esm(() => {
|
|
|
111789
111991
|
|
|
111790
111992
|
// src/lib/recurring-recovery.ts
|
|
111791
111993
|
import { constants as constants26, closeSync as closeSync27, fsyncSync as fsyncSync8, fstatSync as fstatSync27, lstatSync as lstatSync37, mkdirSync as mkdirSync21, openSync as openSync27, readSync as readSync19, realpathSync as realpathSync17, renameSync as renameSync12, unlinkSync as unlinkSync8, writeFileSync as writeFileSync19 } from "fs";
|
|
111792
|
-
import { dirname as dirname35, isAbsolute as
|
|
111994
|
+
import { dirname as dirname35, isAbsolute as isAbsolute34, join as join59, resolve as resolve34 } from "path";
|
|
111793
111995
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
111794
111996
|
|
|
111795
111997
|
class RecoveryOwner {
|
|
@@ -111797,7 +111999,7 @@ class RecoveryOwner {
|
|
|
111797
111999
|
parents = [];
|
|
111798
112000
|
constructor(directory2) {
|
|
111799
112001
|
this.directory = directory2;
|
|
111800
|
-
if (!
|
|
112002
|
+
if (!isAbsolute34(directory2) || resolve34(directory2) !== directory2 || realpathSync17(directory2) !== directory2)
|
|
111801
112003
|
invalid6();
|
|
111802
112004
|
for (let path = directory2;; path = dirname35(path)) {
|
|
111803
112005
|
const stat3 = lstatSync37(path);
|
|
@@ -111932,7 +112134,7 @@ function base2(customer, organizationId) {
|
|
|
111932
112134
|
};
|
|
111933
112135
|
}
|
|
111934
112136
|
function create3(directory2, intent) {
|
|
111935
|
-
if (!
|
|
112137
|
+
if (!isAbsolute34(directory2) || resolve34(directory2) !== directory2 || realpathSync17(dirname35(directory2)) !== dirname35(directory2))
|
|
111936
112138
|
invalid6();
|
|
111937
112139
|
mkdirSync21(directory2, { mode: 448 });
|
|
111938
112140
|
const owner2 = new RecoveryOwner(directory2), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -112095,7 +112297,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
112095
112297
|
});
|
|
112096
112298
|
|
|
112097
112299
|
// src/lib/recurring-surface.ts
|
|
112098
|
-
import { isAbsolute as
|
|
112300
|
+
import { isAbsolute as isAbsolute35 } from "path";
|
|
112099
112301
|
function recurringMcpSchema(action) {
|
|
112100
112302
|
return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
|
|
112101
112303
|
}
|
|
@@ -112200,7 +112402,7 @@ var init_recurring_surface = __esm(() => {
|
|
|
112200
112402
|
uuid12 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
112201
112403
|
context = { userId: uuid12.optional(), membershipId: uuid12.optional() };
|
|
112202
112404
|
page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
|
|
112203
|
-
directory2 = exports_external.string().max(4096).refine(
|
|
112405
|
+
directory2 = exports_external.string().max(4096).refine(isAbsolute35, "Use an absolute recovery directory");
|
|
112204
112406
|
email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
112205
112407
|
code = exports_external.string().regex(/^\d{6}$/);
|
|
112206
112408
|
recurringSurfaceSchemas = {
|
|
@@ -114986,15 +115188,42 @@ var init_remote_invitation_tools = __esm(() => {
|
|
|
114986
115188
|
});
|
|
114987
115189
|
|
|
114988
115190
|
// src/lib/private-publication-customer.ts
|
|
115191
|
+
function preparePrivatePublicationSession(requested) {
|
|
115192
|
+
const selectors = [
|
|
115193
|
+
"HASNA_PROFILE",
|
|
115194
|
+
"HASNA_HOME",
|
|
115195
|
+
"HASNA_CONFIG_HOME",
|
|
115196
|
+
"HASNA_STATION",
|
|
115197
|
+
"HASNA_SKILLS_API_URL",
|
|
115198
|
+
"SKILLS_API_URL",
|
|
115199
|
+
"HASNA_SKILLS_API_KEY_OVERRIDE",
|
|
115200
|
+
"HASNA_SKILLS_API_KEY_REF",
|
|
115201
|
+
"HASNA_SKILLS_API_KEY",
|
|
115202
|
+
"SKILLS_API_KEY"
|
|
115203
|
+
];
|
|
115204
|
+
const before2 = new Map(selectors.map((key2) => [key2, process.env[key2]]));
|
|
115205
|
+
const profile = selectedSkillsProfile(process.env), pending = prepareProfileWorkspace("Manage private publications");
|
|
115206
|
+
const captured = requested ? { ...requested } : undefined;
|
|
115207
|
+
const unchanged3 = () => {
|
|
115208
|
+
if (selectors.some((key2) => process.env[key2] !== before2.get(key2)) || selectedSkillsProfile(process.env) !== profile)
|
|
115209
|
+
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.");
|
|
115210
|
+
};
|
|
115211
|
+
return { origin: pending.origin, async verify(email5, code2) {
|
|
115212
|
+
unchanged3();
|
|
115213
|
+
const target = await pending.resolve();
|
|
115214
|
+
const context2 = captured ?? target.context;
|
|
115215
|
+
if (!context2 || !publicationUuid(context2.userId) || !publicationUuid(context2.membershipId) || target.context && (context2.userId !== target.context.userId || context2.membershipId !== target.context.membershipId))
|
|
115216
|
+
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide the observed user and membership IDs, or select an enrolled workspace profile.");
|
|
115217
|
+
unchanged3();
|
|
115218
|
+
target.unchanged();
|
|
115219
|
+
const client2 = await new RemoteSkillsAuthClient(target.origin).openPrivatePublications(email5, code2, context2);
|
|
115220
|
+
unchanged3();
|
|
115221
|
+
target.unchanged();
|
|
115222
|
+
return client2;
|
|
115223
|
+
} };
|
|
115224
|
+
}
|
|
114989
115225
|
async function privatePublicationSession(email5, code2, requested) {
|
|
114990
|
-
|
|
114991
|
-
const context2 = requested ?? target.context;
|
|
114992
|
-
if (!context2 || !publicationUuid(context2.userId) || !publicationUuid(context2.membershipId) || target.context && (context2.userId !== target.context.userId || context2.membershipId !== target.context.membershipId))
|
|
114993
|
-
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide the observed user and membership IDs, or select an enrolled workspace profile.");
|
|
114994
|
-
target.unchanged();
|
|
114995
|
-
const client2 = await new RemoteSkillsAuthClient(target.origin).openPrivatePublications(email5, code2, context2);
|
|
114996
|
-
target.unchanged();
|
|
114997
|
-
return client2;
|
|
115226
|
+
return preparePrivatePublicationSession(requested).verify(email5, code2);
|
|
114998
115227
|
}
|
|
114999
115228
|
function privatePublicationCustomerError(error61) {
|
|
115000
115229
|
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 };
|
|
@@ -115003,14 +115232,15 @@ var init_private_publication_customer = __esm(() => {
|
|
|
115003
115232
|
init_remote_auth();
|
|
115004
115233
|
init_remote_private_publications();
|
|
115005
115234
|
init_workspace_profile();
|
|
115235
|
+
init_instance_credentials();
|
|
115006
115236
|
});
|
|
115007
115237
|
|
|
115008
115238
|
// src/lib/private-publication-recovery.ts
|
|
115009
115239
|
import { constants as constants27, closeSync as closeSync28, fsyncSync as fsyncSync9, fstatSync as fstatSync28, lstatSync as lstatSync38, mkdirSync as mkdirSync25, openSync as openSync28, readSync as readSync20, realpathSync as realpathSync18, renameSync as renameSync13, unlinkSync as unlinkSync9, writeFileSync as writeFileSync22 } from "fs";
|
|
115010
|
-
import { dirname as dirname38, isAbsolute as
|
|
115240
|
+
import { dirname as dirname38, isAbsolute as isAbsolute36, join as join64, resolve as resolve35 } from "path";
|
|
115011
115241
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
115012
115242
|
function safeDirectory(directory3) {
|
|
115013
|
-
if (!
|
|
115243
|
+
if (!isAbsolute36(directory3) || directory3 !== resolve35(directory3) || realpathSync18(directory3) !== directory3)
|
|
115014
115244
|
return fail5();
|
|
115015
115245
|
for (let path = directory3;; path = dirname38(path)) {
|
|
115016
115246
|
const stat3 = lstatSync38(path);
|
|
@@ -115148,7 +115378,7 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
115148
115378
|
phase: "prepared",
|
|
115149
115379
|
intent: null
|
|
115150
115380
|
};
|
|
115151
|
-
if (!
|
|
115381
|
+
if (!isAbsolute36(recoveryDirectory) || resolve35(recoveryDirectory) !== recoveryDirectory || realpathSync18(dirname38(recoveryDirectory)) !== dirname38(recoveryDirectory))
|
|
115152
115382
|
return fail5();
|
|
115153
115383
|
mkdirSync25(recoveryDirectory, { mode: 448 });
|
|
115154
115384
|
safeDirectory(recoveryDirectory);
|
|
@@ -115249,10 +115479,10 @@ var init_private_publication_recovery = __esm(() => {
|
|
|
115249
115479
|
});
|
|
115250
115480
|
|
|
115251
115481
|
// src/mcp/private-publication-tools.ts
|
|
115252
|
-
import { isAbsolute as
|
|
115482
|
+
import { isAbsolute as isAbsolute37 } from "path";
|
|
115253
115483
|
function registerPrivatePublicationTools(server) {
|
|
115254
115484
|
const uuid9 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
115255
|
-
const directory3 = exports_external.string().max(4096).refine(
|
|
115485
|
+
const directory3 = exports_external.string().max(4096).refine(isAbsolute37, "Use an absolute local directory");
|
|
115256
115486
|
const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory3 };
|
|
115257
115487
|
const description = "Manage a private source publication using fresh workspace-bound verification and a host-local recovery directory. Publishing requires explicit UUID current-version comparison and upload consent. Resume reuses immutable saved bytes and intent; an uncertain PUT is finalized for server verification, never uploaded twice. Sessions and signed URLs are not returned or persisted. Private execution is unavailable. Host request history may contain the supplied verification code.";
|
|
115258
115488
|
const handler = (action) => async (value) => {
|
|
@@ -115713,14 +115943,18 @@ var exports_runtime_mcp = {};
|
|
|
115713
115943
|
__export(exports_runtime_mcp, {
|
|
115714
115944
|
handleMcp: () => handleMcp
|
|
115715
115945
|
});
|
|
115716
|
-
import { existsSync as existsSync33, mkdirSync as mkdirSync26, readFileSync as readFileSync42, writeFileSync as writeFileSync23 } from "fs";
|
|
115946
|
+
import { existsSync as existsSync33, lstatSync as lstatSync39, mkdirSync as mkdirSync26, readFileSync as readFileSync42, renameSync as renameSync14, rmdirSync as rmdirSync4, statSync as statSync22, writeFileSync as writeFileSync23 } from "fs";
|
|
115947
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
115717
115948
|
import { homedir as homedir10 } from "os";
|
|
115718
|
-
import { dirname as dirname39, join as join65 } from "path";
|
|
115949
|
+
import { dirname as dirname39, isAbsolute as isAbsolute38, join as join65 } from "path";
|
|
115950
|
+
import { isDeepStrictEqual as isDeepStrictEqual16, stripVTControlCharacters } from "util";
|
|
115719
115951
|
async function handleMcp(options) {
|
|
115720
115952
|
if (options.register) {
|
|
115721
115953
|
let agents;
|
|
115954
|
+
let environment;
|
|
115722
115955
|
try {
|
|
115723
115956
|
agents = resolveAgents(options.register);
|
|
115957
|
+
environment = skillsMcpRegistrationEnvironment(process.env, options.apiUrl);
|
|
115724
115958
|
} catch (err) {
|
|
115725
115959
|
const error61 = err.message;
|
|
115726
115960
|
if (options.json) {
|
|
@@ -115734,7 +115968,7 @@ async function handleMcp(options) {
|
|
|
115734
115968
|
const command = findCommandOnPath(MCP_COMMAND_NAME);
|
|
115735
115969
|
const results2 = [];
|
|
115736
115970
|
for (const agent of agents) {
|
|
115737
|
-
const result2 = await registerMcpForAgent(agent, command);
|
|
115971
|
+
const result2 = await registerMcpForAgent(agent, command, environment);
|
|
115738
115972
|
results2.push(result2);
|
|
115739
115973
|
if (!options.json) {
|
|
115740
115974
|
const label = result2.path ? `${agent} (${result2.path})` : agent;
|
|
@@ -115751,96 +115985,193 @@ async function handleMcp(options) {
|
|
|
115751
115985
|
const { startMcpStdio: startMcpStdio2 } = await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
|
|
115752
115986
|
await startMcpStdio2();
|
|
115753
115987
|
}
|
|
115754
|
-
async function registerMcpForAgent(agent, command) {
|
|
115988
|
+
async function registerMcpForAgent(agent, command, environment) {
|
|
115989
|
+
const server2 = { command, args: ["--stdio"], ...Object.keys(environment).length ? { env: environment } : {} };
|
|
115755
115990
|
switch (agent) {
|
|
115756
115991
|
case "claude":
|
|
115757
|
-
return registerClaudeMcp(command);
|
|
115992
|
+
return registerClaudeMcp(command, server2, environment);
|
|
115758
115993
|
case "codex":
|
|
115759
|
-
return registerCodexMcp(command);
|
|
115994
|
+
return registerCodexMcp(command, environment);
|
|
115760
115995
|
case "gemini":
|
|
115761
|
-
return registerJsonMcpServer(agent, join65(homedir10(), ".gemini", "settings.json"), "mcpServers",
|
|
115762
|
-
command,
|
|
115763
|
-
args: []
|
|
115764
|
-
});
|
|
115996
|
+
return registerJsonMcpServer(agent, join65(homedir10(), ".gemini", "settings.json"), "mcpServers", server2);
|
|
115765
115997
|
case "pi":
|
|
115766
|
-
return registerJsonMcpServer(agent, join65(homedir10(), ".pi", "agent", "mcp.json"), "mcpServers",
|
|
115767
|
-
command,
|
|
115768
|
-
args: []
|
|
115769
|
-
});
|
|
115998
|
+
return registerJsonMcpServer(agent, join65(homedir10(), ".pi", "agent", "mcp.json"), "mcpServers", server2);
|
|
115770
115999
|
case "opencode":
|
|
115771
|
-
return registerOpenCodeMcp(command);
|
|
116000
|
+
return registerOpenCodeMcp(command, environment);
|
|
115772
116001
|
case "cursor":
|
|
115773
|
-
return registerJsonMcpServer(agent, join65(homedir10(), ".cursor", "mcp.json"), "mcpServers",
|
|
115774
|
-
command,
|
|
115775
|
-
args: []
|
|
115776
|
-
});
|
|
116002
|
+
return registerJsonMcpServer(agent, join65(homedir10(), ".cursor", "mcp.json"), "mcpServers", server2);
|
|
115777
116003
|
case "windsurf":
|
|
115778
|
-
return registerJsonMcpServer(agent, join65(homedir10(), ".windsurf", "mcp.json"), "mcpServers",
|
|
115779
|
-
command,
|
|
115780
|
-
args: []
|
|
115781
|
-
});
|
|
116004
|
+
return registerJsonMcpServer(agent, join65(homedir10(), ".windsurf", "mcp.json"), "mcpServers", server2);
|
|
115782
116005
|
default:
|
|
115783
116006
|
return { agent, success: false, error: `Unknown agent: ${agent}. Available: ${AGENT_TARGETS.join(", ")}, all` };
|
|
115784
116007
|
}
|
|
115785
116008
|
}
|
|
115786
|
-
async function registerClaudeMcp(command) {
|
|
115787
|
-
const
|
|
116009
|
+
async function registerClaudeMcp(command, server2, environment) {
|
|
116010
|
+
const args2 = ["claude", "mcp", "add", "-s", "user", ...Object.entries(environment).flatMap(([key2, value]) => ["--env", `${key2}=${value}`]), "--transport", "stdio", MCP_SERVER_NAME, "--", command, "--stdio"];
|
|
116011
|
+
const cliCommand = args2.map(skillsShellArgument).join(" ");
|
|
116012
|
+
const desired = { type: "stdio", ...server2, env: environment };
|
|
115788
116013
|
try {
|
|
115789
|
-
const
|
|
115790
|
-
|
|
115791
|
-
|
|
116014
|
+
const path = claudeUserConfigPath();
|
|
116015
|
+
const before2 = withClaudeConfigLock(path, () => {
|
|
116016
|
+
if (claudeUserConfigPath() !== path)
|
|
116017
|
+
throw new Error;
|
|
116018
|
+
const bytes = readClaudeConfig(path);
|
|
116019
|
+
if (bytes !== null) {
|
|
116020
|
+
const backup = `${path}.skills-mcp-${randomUUID10()}.backup`;
|
|
116021
|
+
writeFileSync23(backup, bytes, { flag: "wx", mode: 384 });
|
|
116022
|
+
if (!readFileSync42(backup).equals(bytes))
|
|
116023
|
+
throw new Error;
|
|
116024
|
+
}
|
|
116025
|
+
return bytes;
|
|
115792
116026
|
});
|
|
115793
|
-
|
|
115794
|
-
|
|
115795
|
-
|
|
115796
|
-
|
|
115797
|
-
|
|
115798
|
-
|
|
115799
|
-
|
|
116027
|
+
let exitCode, duplicateAccepted = false, cliUnavailable = false;
|
|
116028
|
+
const proc = (() => {
|
|
116029
|
+
try {
|
|
116030
|
+
return Bun.spawn(args2, { stdout: "pipe", stderr: "pipe" });
|
|
116031
|
+
} catch (error61) {
|
|
116032
|
+
if (!isPlainObject4(error61) || error61.code !== "ENOENT")
|
|
116033
|
+
throw new Error;
|
|
116034
|
+
cliUnavailable = true;
|
|
116035
|
+
return;
|
|
116036
|
+
}
|
|
116037
|
+
})();
|
|
116038
|
+
if (proc) {
|
|
116039
|
+
const [stdout, stderr, status] = await Promise.all([
|
|
116040
|
+
new Response(proc.stdout).text(),
|
|
116041
|
+
new Response(proc.stderr).text(),
|
|
116042
|
+
proc.exited
|
|
116043
|
+
]);
|
|
116044
|
+
exitCode = status;
|
|
116045
|
+
const diagnostic = stripVTControlCharacters(stderr).trim();
|
|
116046
|
+
duplicateAccepted = exitCode === 1 && stdout.trim() === "" && (diagnostic === `MCP server ${MCP_SERVER_NAME} already exists in user config` || diagnostic === `Error: MCP server ${MCP_SERVER_NAME} already exists in user config`);
|
|
116047
|
+
if (exitCode !== 0 && !duplicateAccepted)
|
|
116048
|
+
throw new Error;
|
|
115800
116049
|
}
|
|
115801
|
-
|
|
115802
|
-
|
|
115803
|
-
|
|
115804
|
-
|
|
115805
|
-
|
|
115806
|
-
|
|
115807
|
-
|
|
115808
|
-
|
|
115809
|
-
|
|
115810
|
-
|
|
115811
|
-
|
|
115812
|
-
|
|
115813
|
-
|
|
116050
|
+
return withClaudeConfigLock(path, () => {
|
|
116051
|
+
if (claudeUserConfigPath() !== path)
|
|
116052
|
+
throw new Error;
|
|
116053
|
+
const current = readClaudeConfig(path);
|
|
116054
|
+
const previous = parseClaudeConfig(before2), data = parseClaudeConfig(current);
|
|
116055
|
+
if (exitCode === 0) {
|
|
116056
|
+
const actual = isPlainObject4(data.mcpServers) ? data.mcpServers[MCP_SERVER_NAME] : undefined;
|
|
116057
|
+
if (!isDeepStrictEqual16(withoutClaudeSkills(previous), withoutClaudeSkills(data)) || !isPlainObject4(actual) || !isDeepStrictEqual16({ ...actual, env: actual.env ?? {} }, desired))
|
|
116058
|
+
throw new Error;
|
|
116059
|
+
} else {
|
|
116060
|
+
if (!cliUnavailable && (!duplicateAccepted || !isPlainObject4(previous.mcpServers) || !previous.mcpServers[MCP_SERVER_NAME]))
|
|
116061
|
+
throw new Error;
|
|
116062
|
+
if (before2 === null ? current !== null : current === null || !current.equals(before2))
|
|
116063
|
+
throw new Error;
|
|
116064
|
+
data.mcpServers = { ...data.mcpServers, [MCP_SERVER_NAME]: desired };
|
|
116065
|
+
const next = Buffer.from(`${JSON.stringify(data, null, 2)}
|
|
116066
|
+
`);
|
|
116067
|
+
const temporary = `${path}.skills-mcp-${randomUUID10()}.tmp`;
|
|
116068
|
+
writeFileSync23(temporary, next, { flag: "wx", mode: 384 });
|
|
116069
|
+
if (!readFileSync42(temporary).equals(next))
|
|
116070
|
+
throw new Error;
|
|
116071
|
+
const latest = readClaudeConfig(path);
|
|
116072
|
+
if (claudeUserConfigPath() !== path || (before2 === null ? latest !== null : latest === null || !latest.equals(before2)))
|
|
116073
|
+
throw new Error;
|
|
116074
|
+
renameSync14(temporary, path);
|
|
116075
|
+
if (!readFileSync42(path).equals(next))
|
|
116076
|
+
throw new Error;
|
|
116077
|
+
}
|
|
116078
|
+
return { agent: "claude", success: true, path, command: cliCommand };
|
|
115814
116079
|
});
|
|
116080
|
+
} catch {
|
|
115815
116081
|
return {
|
|
115816
|
-
|
|
116082
|
+
agent: "claude",
|
|
116083
|
+
success: false,
|
|
115817
116084
|
command: cliCommand,
|
|
115818
|
-
error:
|
|
116085
|
+
error: "Could not safely update the Claude user MCP configuration; native admission or config checks refused the update"
|
|
115819
116086
|
};
|
|
115820
116087
|
}
|
|
115821
116088
|
}
|
|
115822
|
-
function
|
|
116089
|
+
function claudeUserConfigPath() {
|
|
116090
|
+
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
116091
|
+
if (override !== undefined && (!override || !isAbsolute38(override) || /[\x00-\x1f\x7f]/.test(override)))
|
|
116092
|
+
throw new Error;
|
|
116093
|
+
const modern = join65(override || homedir10(), process.env.CLAUDE_CODE_CUSTOM_OAUTH_URL ? ".claude-custom-oauth.json" : ".claude.json");
|
|
116094
|
+
const legacy = join65(override ?? join65(homedir10(), ".claude"), ".config.json");
|
|
116095
|
+
if (existsSync33(legacy)) {
|
|
116096
|
+
const info = lstatSync39(legacy);
|
|
116097
|
+
if (!info.isFile())
|
|
116098
|
+
throw new Error;
|
|
116099
|
+
if (info.size > 0 || (info.mode & 146) !== 0 && !existsSync33(modern))
|
|
116100
|
+
return legacy;
|
|
116101
|
+
}
|
|
116102
|
+
return modern;
|
|
116103
|
+
}
|
|
116104
|
+
function readClaudeConfig(path) {
|
|
116105
|
+
if (!existsSync33(path))
|
|
116106
|
+
return null;
|
|
116107
|
+
const info = lstatSync39(path);
|
|
116108
|
+
if (!info.isFile() || info.size > 16777216)
|
|
116109
|
+
throw new Error;
|
|
116110
|
+
const bytes = readFileSync42(path);
|
|
116111
|
+
parseClaudeConfig(bytes);
|
|
116112
|
+
return bytes;
|
|
116113
|
+
}
|
|
116114
|
+
function parseClaudeConfig(bytes) {
|
|
116115
|
+
const data = bytes === null ? {} : JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
116116
|
+
if (!isPlainObject4(data) || data.mcpServers !== undefined && !isPlainObject4(data.mcpServers))
|
|
116117
|
+
throw new Error;
|
|
116118
|
+
return data;
|
|
116119
|
+
}
|
|
116120
|
+
function withoutClaudeSkills(data) {
|
|
116121
|
+
const rest2 = { ...data }, servers = { ...data.mcpServers };
|
|
116122
|
+
delete servers[MCP_SERVER_NAME];
|
|
116123
|
+
if (Object.keys(servers).length)
|
|
116124
|
+
rest2.mcpServers = servers;
|
|
116125
|
+
else
|
|
116126
|
+
delete rest2.mcpServers;
|
|
116127
|
+
return rest2;
|
|
116128
|
+
}
|
|
116129
|
+
function withClaudeConfigLock(path, action) {
|
|
116130
|
+
mkdirSync26(dirname39(path), { recursive: true });
|
|
116131
|
+
const lock = `${path}.lock`;
|
|
116132
|
+
mkdirSync26(lock, { mode: 448 });
|
|
116133
|
+
const owned = statSync22(lock);
|
|
116134
|
+
try {
|
|
116135
|
+
return action();
|
|
116136
|
+
} finally {
|
|
116137
|
+
const current = lstatSync39(lock);
|
|
116138
|
+
if (current.isDirectory() && current.dev === owned.dev && current.ino === owned.ino) {
|
|
116139
|
+
rmdirSync4(lock);
|
|
116140
|
+
}
|
|
116141
|
+
}
|
|
116142
|
+
}
|
|
116143
|
+
function registerCodexMcp(command, environment) {
|
|
115823
116144
|
const path = join65(homedir10(), ".codex", "config.toml");
|
|
116145
|
+
const body = `command = ${JSON.stringify(command)}
|
|
116146
|
+
args = ["--stdio"]${Object.keys(environment).length ? `
|
|
116147
|
+
env = { ${Object.entries(environment).map(([key2, value]) => `${JSON.stringify(key2)} = ${JSON.stringify(value)}`).join(", ")} }` : ""}`;
|
|
115824
116148
|
const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
|
|
115825
|
-
|
|
116149
|
+
${body}`;
|
|
115826
116150
|
try {
|
|
115827
116151
|
const current = existsSync33(path) ? readFileSync42(path, "utf-8") : "";
|
|
115828
|
-
|
|
116152
|
+
const before2 = Bun.TOML.parse(current);
|
|
116153
|
+
const next = upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, body);
|
|
116154
|
+
const after2 = Bun.TOML.parse(next);
|
|
116155
|
+
if (!isDeepStrictEqual16(withoutSkillsMcp(before2), withoutSkillsMcp(after2)))
|
|
116156
|
+
throw new Error;
|
|
116157
|
+
writeTextFile(path, next);
|
|
115829
116158
|
return { agent: "codex", success: true, path, config: config2 };
|
|
115830
116159
|
} catch (err) {
|
|
115831
|
-
return { agent: "codex", success: false, path, config: config2, error:
|
|
116160
|
+
return { agent: "codex", success: false, path, config: config2, error: "Could not update the Codex MCP configuration" };
|
|
115832
116161
|
}
|
|
115833
116162
|
}
|
|
115834
|
-
function registerOpenCodeMcp(command) {
|
|
116163
|
+
function registerOpenCodeMcp(command, environment) {
|
|
115835
116164
|
const path = join65(homedir10(), ".config", "opencode", "opencode.json");
|
|
116165
|
+
const server2 = {
|
|
116166
|
+
type: "local",
|
|
116167
|
+
command: [command, "--stdio"],
|
|
116168
|
+
enabled: true,
|
|
116169
|
+
...Object.keys(environment).length ? { environment } : {}
|
|
116170
|
+
};
|
|
115836
116171
|
const config2 = JSON.stringify({
|
|
115837
116172
|
$schema: "https://opencode.ai/config.json",
|
|
115838
116173
|
mcp: {
|
|
115839
|
-
[MCP_SERVER_NAME]:
|
|
115840
|
-
type: "local",
|
|
115841
|
-
command: [command],
|
|
115842
|
-
enabled: true
|
|
115843
|
-
}
|
|
116174
|
+
[MCP_SERVER_NAME]: server2
|
|
115844
116175
|
}
|
|
115845
116176
|
}, null, 2);
|
|
115846
116177
|
try {
|
|
@@ -115848,16 +116179,12 @@ function registerOpenCodeMcp(command) {
|
|
|
115848
116179
|
if (!data.$schema)
|
|
115849
116180
|
data.$schema = "https://opencode.ai/config.json";
|
|
115850
116181
|
const mcp = isPlainObject4(data.mcp) ? data.mcp : {};
|
|
115851
|
-
mcp[MCP_SERVER_NAME] =
|
|
115852
|
-
type: "local",
|
|
115853
|
-
command: [command],
|
|
115854
|
-
enabled: true
|
|
115855
|
-
};
|
|
116182
|
+
mcp[MCP_SERVER_NAME] = server2;
|
|
115856
116183
|
data.mcp = mcp;
|
|
115857
116184
|
writeJsonObject(path, data);
|
|
115858
116185
|
return { agent: "opencode", success: true, path, config: config2 };
|
|
115859
116186
|
} catch (err) {
|
|
115860
|
-
return { agent: "opencode", success: false, path, config: config2, error:
|
|
116187
|
+
return { agent: "opencode", success: false, path, config: config2, error: "Could not update the OpenCode MCP configuration" };
|
|
115861
116188
|
}
|
|
115862
116189
|
}
|
|
115863
116190
|
function registerJsonMcpServer(agent, path, containerKey, server2) {
|
|
@@ -115870,7 +116197,7 @@ function registerJsonMcpServer(agent, path, containerKey, server2) {
|
|
|
115870
116197
|
writeJsonObject(path, data);
|
|
115871
116198
|
return { agent, success: true, path, config: config2 };
|
|
115872
116199
|
} catch (err) {
|
|
115873
|
-
return { agent, success: false, path, config: config2, error:
|
|
116200
|
+
return { agent, success: false, path, config: config2, error: "Could not update the agent MCP configuration" };
|
|
115874
116201
|
}
|
|
115875
116202
|
}
|
|
115876
116203
|
function readJsonObject2(path) {
|
|
@@ -115897,24 +116224,37 @@ function writeTextFile(path, content) {
|
|
|
115897
116224
|
function upsertTomlSection(content, header, body) {
|
|
115898
116225
|
const sectionLines = [header, ...body.trim().split(/\r?\n/)];
|
|
115899
116226
|
const lines = content.trimEnd() ? content.trimEnd().split(/\r?\n/) : [];
|
|
115900
|
-
const
|
|
115901
|
-
|
|
115902
|
-
|
|
115903
|
-
|
|
115904
|
-
|
|
115905
|
-
|
|
115906
|
-
|
|
115907
|
-
|
|
115908
|
-
|
|
115909
|
-
end = i;
|
|
115910
|
-
break;
|
|
116227
|
+
const result2 = [];
|
|
116228
|
+
let owned = false, inserted = false;
|
|
116229
|
+
for (const line of lines) {
|
|
116230
|
+
if (/^\s*\[/.test(line)) {
|
|
116231
|
+
owned = /^\s*\[\s*(?:mcp_servers|"mcp_servers"|'mcp_servers')\s*\.\s*(?:skills|"skills"|'skills')\s*(?:\.|\])/.test(line);
|
|
116232
|
+
if (owned && !inserted) {
|
|
116233
|
+
result2.push(...sectionLines, "");
|
|
116234
|
+
inserted = true;
|
|
116235
|
+
}
|
|
115911
116236
|
}
|
|
116237
|
+
if (!owned)
|
|
116238
|
+
result2.push(line);
|
|
115912
116239
|
}
|
|
115913
|
-
|
|
115914
|
-
|
|
116240
|
+
if (!inserted)
|
|
116241
|
+
result2.push(...result2.length ? [""] : [], ...sectionLines);
|
|
116242
|
+
return `${result2.join(`
|
|
115915
116243
|
`)}
|
|
115916
116244
|
`;
|
|
115917
116245
|
}
|
|
116246
|
+
function withoutSkillsMcp(config2) {
|
|
116247
|
+
const preserved = { ...config2 };
|
|
116248
|
+
if (isPlainObject4(preserved.mcp_servers)) {
|
|
116249
|
+
const servers = { ...preserved.mcp_servers };
|
|
116250
|
+
delete servers[MCP_SERVER_NAME];
|
|
116251
|
+
if (Object.keys(servers).length)
|
|
116252
|
+
preserved.mcp_servers = servers;
|
|
116253
|
+
else
|
|
116254
|
+
delete preserved.mcp_servers;
|
|
116255
|
+
}
|
|
116256
|
+
return preserved;
|
|
116257
|
+
}
|
|
115918
116258
|
function findCommandOnPath(command) {
|
|
115919
116259
|
const pathValue = process.env.PATH || "";
|
|
115920
116260
|
for (const dir of pathValue.split(":")) {
|
|
@@ -115933,6 +116273,8 @@ var MCP_SERVER_NAME = "skills", MCP_COMMAND_NAME = "skills-mcp";
|
|
|
115933
116273
|
var init_runtime_mcp = __esm(() => {
|
|
115934
116274
|
init_source();
|
|
115935
116275
|
init_installer();
|
|
116276
|
+
init_credential_profile_command();
|
|
116277
|
+
init_mcp_registration_environment();
|
|
115936
116278
|
});
|
|
115937
116279
|
|
|
115938
116280
|
// src/cli/commands/remote-account.ts
|
|
@@ -116126,7 +116468,7 @@ var init_reviewed_runtime_lock = __esm(() => {
|
|
|
116126
116468
|
});
|
|
116127
116469
|
|
|
116128
116470
|
// src/cli/commands/runtime-copyfile.ts
|
|
116129
|
-
import { createHash as createHash40, randomUUID as
|
|
116471
|
+
import { createHash as createHash40, randomUUID as randomUUID11 } from "crypto";
|
|
116130
116472
|
import { Readable } from "stream";
|
|
116131
116473
|
import { createGunzip as createGunzip2 } from "zlib";
|
|
116132
116474
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
@@ -116134,16 +116476,16 @@ import {
|
|
|
116134
116476
|
chmodSync as chmodSync4,
|
|
116135
116477
|
copyFileSync,
|
|
116136
116478
|
existsSync as existsSync34,
|
|
116137
|
-
lstatSync as
|
|
116479
|
+
lstatSync as lstatSync40,
|
|
116138
116480
|
mkdirSync as mkdirSync27,
|
|
116139
116481
|
readFileSync as readFileSync43,
|
|
116140
116482
|
readdirSync as readdirSync24,
|
|
116141
116483
|
readlinkSync as readlinkSync8,
|
|
116142
116484
|
realpathSync as realpathSync19,
|
|
116143
|
-
renameSync as
|
|
116485
|
+
renameSync as renameSync15,
|
|
116144
116486
|
writeFileSync as writeFileSync24
|
|
116145
116487
|
} from "fs";
|
|
116146
|
-
import { basename as basename21, delimiter as delimiter3, dirname as dirname40, isAbsolute as
|
|
116488
|
+
import { basename as basename21, delimiter as delimiter3, dirname as dirname40, isAbsolute as isAbsolute39, join as join66, relative as relative13, resolve as resolve36, sep as sep18 } from "path";
|
|
116147
116489
|
function oldLauncherState(item) {
|
|
116148
116490
|
if (item.oldShape === "pinned")
|
|
116149
116491
|
return { shape: "pinned", runtime: item.oldRuntime, cwd: item.oldCwd, target: item.oldTarget, sha256: item.oldSha256, format: item.oldFormat, profile: item.oldProfile };
|
|
@@ -116169,7 +116511,7 @@ function assertLauncherRecordShapes(item, expectedProfile) {
|
|
|
116169
116511
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
116170
116512
|
continue;
|
|
116171
116513
|
}
|
|
116172
|
-
if (shape !== "pinned" || typeof runtime !== "string" || !
|
|
116514
|
+
if (shape !== "pinned" || typeof runtime !== "string" || !isAbsolute39(runtime) || typeof cwd2 !== "string" || !isAbsolute39(cwd2) || typeof sha7 !== "string" || !hex4.test(sha7)) {
|
|
116173
116515
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
116174
116516
|
}
|
|
116175
116517
|
const target = side === "old" ? item.oldTarget : item.newTarget;
|
|
@@ -116197,7 +116539,7 @@ function verifyTargetPrerequisites(manifest, packageRoot, home, cwd2, pathValue)
|
|
|
116197
116539
|
throw new Error("RUNTIME_PREREQUISITE_CONTRACT_INVALID");
|
|
116198
116540
|
}
|
|
116199
116541
|
const entry = join66(packageRoot, contract.entry);
|
|
116200
|
-
if (!entryExists(entry) || !
|
|
116542
|
+
if (!entryExists(entry) || !lstatSync40(entry).isFile() || lstatSync40(entry).isSymbolicLink())
|
|
116201
116543
|
throw new Error("RUNTIME_PREREQUISITE_ENTRY_MISSING");
|
|
116202
116544
|
const entrySha256 = hash6(readFileSync43(entry));
|
|
116203
116545
|
const env3 = { HOME: home, PATH: pathValue, BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0" };
|
|
@@ -116256,11 +116598,11 @@ function hash6(bytes) {
|
|
|
116256
116598
|
}
|
|
116257
116599
|
function isWithin(parent, child2) {
|
|
116258
116600
|
const rel = relative13(parent, child2);
|
|
116259
|
-
return rel === "" || !rel.startsWith(`..${sep18}`) && rel !== ".." && !
|
|
116601
|
+
return rel === "" || !rel.startsWith(`..${sep18}`) && rel !== ".." && !isAbsolute39(rel);
|
|
116260
116602
|
}
|
|
116261
116603
|
function entryExists(path) {
|
|
116262
116604
|
try {
|
|
116263
|
-
|
|
116605
|
+
lstatSync40(path);
|
|
116264
116606
|
return true;
|
|
116265
116607
|
} catch {
|
|
116266
116608
|
return false;
|
|
@@ -116272,7 +116614,7 @@ function assertNoSymlinkAncestors(path) {
|
|
|
116272
116614
|
let current = sep18;
|
|
116273
116615
|
for (const part of parts) {
|
|
116274
116616
|
current = join66(current, part);
|
|
116275
|
-
const stat3 =
|
|
116617
|
+
const stat3 = lstatSync40(current);
|
|
116276
116618
|
if (stat3.isSymbolicLink())
|
|
116277
116619
|
throw new Error("PATH_ANCESTOR_SYMLINK_UNSUPPORTED");
|
|
116278
116620
|
if (!stat3.isDirectory())
|
|
@@ -116287,17 +116629,17 @@ function acquireRuntimeLock(runtimeRoot) {
|
|
|
116287
116629
|
throw new Error("RUNTIME_UPDATE_LOCKED");
|
|
116288
116630
|
}
|
|
116289
116631
|
try {
|
|
116290
|
-
writeJsonPrivate(join66(lockPath, "lock.json"), { operationId:
|
|
116632
|
+
writeJsonPrivate(join66(lockPath, "lock.json"), { operationId: randomUUID11(), pid: process.pid, startedAt: new Date().toISOString() });
|
|
116291
116633
|
} catch {
|
|
116292
116634
|
try {
|
|
116293
|
-
|
|
116635
|
+
renameSync15(lockPath, join66(runtimeRoot, `.copyfile-update-lock-incomplete-${randomUUID11()}`));
|
|
116294
116636
|
} catch {}
|
|
116295
116637
|
throw new Error("RUNTIME_LOCK_INITIALIZATION_FAILED");
|
|
116296
116638
|
}
|
|
116297
116639
|
return () => {
|
|
116298
|
-
const released = join66(runtimeRoot, `.copyfile-update-lock-released-${
|
|
116640
|
+
const released = join66(runtimeRoot, `.copyfile-update-lock-released-${randomUUID11()}`);
|
|
116299
116641
|
writeJsonPrivate(join66(lockPath, "released.json"), { completedAt: new Date().toISOString() });
|
|
116300
|
-
|
|
116642
|
+
renameSync15(lockPath, released);
|
|
116301
116643
|
};
|
|
116302
116644
|
}
|
|
116303
116645
|
function packageBins(pkg) {
|
|
@@ -116305,7 +116647,7 @@ function packageBins(pkg) {
|
|
|
116305
116647
|
const entries = typeof raw === "string" ? [[PACKAGE_NAME.slice(PACKAGE_NAME.lastIndexOf("/") + 1), raw]] : raw && typeof raw === "object" && !Array.isArray(raw) ? Object.entries(raw) : [];
|
|
116306
116648
|
const output2 = {};
|
|
116307
116649
|
for (const [name, value] of entries) {
|
|
116308
|
-
if (!/^[a-zA-Z0-9._-]+$/.test(name) || typeof value !== "string" || !value ||
|
|
116650
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(name) || typeof value !== "string" || !value || isAbsolute39(value)) {
|
|
116309
116651
|
throw new Error("PACKAGE_BIN_INVALID");
|
|
116310
116652
|
}
|
|
116311
116653
|
const normalized2 = value.replaceAll("\\", "/");
|
|
@@ -116333,7 +116675,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
|
|
|
116333
116675
|
const home = realpathSync19(homeInput);
|
|
116334
116676
|
const runtimeRoot = join66(home, ".hasna", "skills", "runtime");
|
|
116335
116677
|
assertNoSymlinkAncestors(runtimeRoot);
|
|
116336
|
-
const runtimeRootStat =
|
|
116678
|
+
const runtimeRootStat = lstatSync40(runtimeRoot);
|
|
116337
116679
|
if (!runtimeRootStat.isDirectory() || runtimeRootStat.isSymbolicLink() || (runtimeRootStat.mode & 63) !== 0) {
|
|
116338
116680
|
throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
|
|
116339
116681
|
}
|
|
@@ -116392,7 +116734,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
|
|
|
116392
116734
|
if (actual !== join66(currentPackageRoot, target))
|
|
116393
116735
|
continue;
|
|
116394
116736
|
const newTarget = join66(runtimeRoot, "__target__", "node_modules", "@hasna", "skills", target);
|
|
116395
|
-
const backupPath = `${path}.skills-prev-${
|
|
116737
|
+
const backupPath = `${path}.skills-prev-${randomUUID11()}`;
|
|
116396
116738
|
if (launcher.kind === "symlink") {
|
|
116397
116739
|
if (resolve36(dirname40(path), launcher.linkTarget) !== actual)
|
|
116398
116740
|
throw new Error("LAUNCHER_SYMLINK_CHAIN_UNSUPPORTED");
|
|
@@ -116605,7 +116947,7 @@ function readTree(root2, includeModes, excludeNpmDependencies = false) {
|
|
|
116605
116947
|
for (const item of readdirSync24(dir).sort()) {
|
|
116606
116948
|
const path = join66(dir, item);
|
|
116607
116949
|
const rel = prefix ? `${prefix}/${item}` : item;
|
|
116608
|
-
const stat3 =
|
|
116950
|
+
const stat3 = lstatSync40(path);
|
|
116609
116951
|
if (excludeNpmDependencies && !prefix && item === "node_modules") {
|
|
116610
116952
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
116611
116953
|
throw new Error("INSTALLED_DEPENDENCY_DIRECTORY_UNSAFE");
|
|
@@ -116641,14 +116983,14 @@ function readTree(root2, includeModes, excludeNpmDependencies = false) {
|
|
|
116641
116983
|
return { entries, digest: hash6(new TextEncoder().encode(JSON.stringify(entries))) };
|
|
116642
116984
|
}
|
|
116643
116985
|
function normalizeModes(root2) {
|
|
116644
|
-
const rootStat =
|
|
116986
|
+
const rootStat = lstatSync40(root2);
|
|
116645
116987
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink())
|
|
116646
116988
|
throw new Error("RUNTIME_ENTRY_TYPE_UNSUPPORTED");
|
|
116647
116989
|
chmodSync4(root2, rootStat.mode & 493);
|
|
116648
116990
|
const walk2 = (dir) => {
|
|
116649
116991
|
for (const item of readdirSync24(dir)) {
|
|
116650
116992
|
const path = join66(dir, item);
|
|
116651
|
-
const stat3 =
|
|
116993
|
+
const stat3 = lstatSync40(path);
|
|
116652
116994
|
if (stat3.isSymbolicLink())
|
|
116653
116995
|
continue;
|
|
116654
116996
|
if (stat3.isDirectory()) {
|
|
@@ -116698,7 +117040,7 @@ function verifyPreimageManifest(runtimePath, receipt, home) {
|
|
|
116698
117040
|
throw new Error("PREIMAGE_CONFIG_BINDING_INVALID");
|
|
116699
117041
|
if (config2.present) {
|
|
116700
117042
|
const backup = join66(runtimePath, "preimage", "configs", relativePath);
|
|
116701
|
-
const stat3 =
|
|
117043
|
+
const stat3 = lstatSync40(backup);
|
|
116702
117044
|
const saved = readFileSync43(backup);
|
|
116703
117045
|
if (!stat3.isFile() || stat3.isSymbolicLink() || hash6(saved) !== config2.sha256 || saved.byteLength !== config2.byteSize)
|
|
116704
117046
|
throw new Error("PREIMAGE_CONFIG_DRIFT");
|
|
@@ -116712,7 +117054,7 @@ function captureConfigPreimages(home, stage) {
|
|
|
116712
117054
|
const sourcePath = join66(home, relativePath);
|
|
116713
117055
|
if (!entryExists(sourcePath))
|
|
116714
117056
|
return { sourcePath, relativePath, present: false };
|
|
116715
|
-
const stat3 =
|
|
117057
|
+
const stat3 = lstatSync40(sourcePath);
|
|
116716
117058
|
if (!stat3.isFile() || stat3.isSymbolicLink())
|
|
116717
117059
|
throw new Error("CONFIG_PREIMAGE_NOT_REGULAR_FILE");
|
|
116718
117060
|
const bytes = readFileSync43(sourcePath);
|
|
@@ -116732,7 +117074,7 @@ function assertConfigUnchanged(configs) {
|
|
|
116732
117074
|
if (present2 !== config2.present)
|
|
116733
117075
|
throw new Error("CONFIG_DRIFT_DURING_UPDATE");
|
|
116734
117076
|
if (present2) {
|
|
116735
|
-
const stat3 =
|
|
117077
|
+
const stat3 = lstatSync40(config2.sourcePath);
|
|
116736
117078
|
if (!stat3.isFile() || stat3.isSymbolicLink() || hash6(readFileSync43(config2.sourcePath)) !== config2.sha256) {
|
|
116737
117079
|
throw new Error("CONFIG_DRIFT_DURING_UPDATE");
|
|
116738
117080
|
}
|
|
@@ -116831,7 +117173,7 @@ function replaceLauncher(item) {
|
|
|
116831
117173
|
const oldState = oldLauncherState(item), newState = newLauncherState(item);
|
|
116832
117174
|
if (!launcherIs(item.path, oldState) || entryExists(item.backupPath))
|
|
116833
117175
|
throw new Error("LAUNCHER_PREIMAGE_DRIFT");
|
|
116834
|
-
const temp = `${item.path}.skills-next-${
|
|
117176
|
+
const temp = `${item.path}.skills-next-${randomUUID11()}`;
|
|
116835
117177
|
try {
|
|
116836
117178
|
materializeLauncher(item.backupPath, oldState);
|
|
116837
117179
|
} catch {
|
|
@@ -116846,15 +117188,15 @@ function replaceLauncher(item) {
|
|
|
116846
117188
|
}
|
|
116847
117189
|
if (!launcherIs(temp, newState))
|
|
116848
117190
|
throw new Error("LAUNCHER_NEW_LINK_READBACK_MISMATCH");
|
|
116849
|
-
|
|
117191
|
+
renameSync15(temp, item.path);
|
|
116850
117192
|
}
|
|
116851
117193
|
function atomicJson(path, value) {
|
|
116852
|
-
const temp = `${path}.next-${
|
|
117194
|
+
const temp = `${path}.next-${randomUUID11()}`;
|
|
116853
117195
|
const bytes = Buffer.from(`${JSON.stringify(value, null, 2)}
|
|
116854
117196
|
`);
|
|
116855
117197
|
writeFileSync24(temp, bytes, { flag: "wx", mode: 384 });
|
|
116856
117198
|
chmodSync4(temp, 384);
|
|
116857
|
-
|
|
117199
|
+
renameSync15(temp, path);
|
|
116858
117200
|
if (!readFileSync43(path).equals(bytes))
|
|
116859
117201
|
throw new Error("RECEIPT_READBACK_MISMATCH");
|
|
116860
117202
|
}
|
|
@@ -116871,10 +117213,10 @@ function persistReceipt(path, value) {
|
|
|
116871
117213
|
const historyRoot = join66(dirname40(path), "receipt-history");
|
|
116872
117214
|
if (!entryExists(historyRoot))
|
|
116873
117215
|
mkdirSync27(historyRoot, { mode: 448 });
|
|
116874
|
-
const historyStat =
|
|
117216
|
+
const historyStat = lstatSync40(historyRoot);
|
|
116875
117217
|
if (!historyStat.isDirectory() || historyStat.isSymbolicLink() || (historyStat.mode & 63) !== 0)
|
|
116876
117218
|
throw new Error("RECEIPT_HISTORY_NOT_PRIVATE");
|
|
116877
|
-
const historyPath = join66(historyRoot, `${value.id}-${String(prior.state)}-${
|
|
117219
|
+
const historyPath = join66(historyRoot, `${value.id}-${String(prior.state)}-${randomUUID11()}.json`);
|
|
116878
117220
|
writeFileSync24(historyPath, priorBytes, { flag: "wx", mode: 256 });
|
|
116879
117221
|
chmodSync4(historyPath, 256);
|
|
116880
117222
|
if (!readFileSync43(historyPath).equals(priorBytes))
|
|
@@ -116895,10 +117237,10 @@ function persistAliasReceipt(path, value) {
|
|
|
116895
117237
|
const history = join66(dirname40(path), "history");
|
|
116896
117238
|
if (!entryExists(history))
|
|
116897
117239
|
mkdirSync27(history, { mode: 448 });
|
|
116898
|
-
const historyStat =
|
|
117240
|
+
const historyStat = lstatSync40(history);
|
|
116899
117241
|
if (!historyStat.isDirectory() || historyStat.isSymbolicLink() || (historyStat.mode & 63) !== 0)
|
|
116900
117242
|
throw new Error("ALIAS_RECEIPT_HISTORY_UNSAFE");
|
|
116901
|
-
const saved = join66(history, `${value.id}-${String(prior.state)}-${
|
|
117243
|
+
const saved = join66(history, `${value.id}-${String(prior.state)}-${randomUUID11()}.json`);
|
|
116902
117244
|
writeFileSync24(saved, priorBytes, { flag: "wx", mode: 256 });
|
|
116903
117245
|
chmodSync4(saved, 256);
|
|
116904
117246
|
if (!readFileSync43(saved).equals(priorBytes))
|
|
@@ -116909,7 +117251,7 @@ function persistAliasReceipt(path, value) {
|
|
|
116909
117251
|
function assertOwnedSafePath(path, home, requireWritable = false) {
|
|
116910
117252
|
assertNoSymlinkAncestors(path);
|
|
116911
117253
|
for (let current = path;; current = dirname40(current)) {
|
|
116912
|
-
const stat3 =
|
|
117254
|
+
const stat3 = lstatSync40(current);
|
|
116913
117255
|
if (!stat3.isDirectory() || ![0, process.getuid?.() ?? -1].includes(stat3.uid) || stat3.mode & 18)
|
|
116914
117256
|
throw new Error("ALIAS_PATH_UNSAFE");
|
|
116915
117257
|
if (current === path && requireWritable && (stat3.uid !== (process.getuid?.() ?? -1) || (stat3.mode & 128) === 0))
|
|
@@ -116957,7 +117299,7 @@ function inspectAliasPackageChain(home, aliasPath, oldLinkTarget, oldTarget, bin
|
|
|
116957
117299
|
assertOwnedSafePath(dirname40(packageLinkPath), home);
|
|
116958
117300
|
let stat3, packageLinkTarget, resolved;
|
|
116959
117301
|
try {
|
|
116960
|
-
stat3 =
|
|
117302
|
+
stat3 = lstatSync40(packageLinkPath);
|
|
116961
117303
|
packageLinkTarget = readlinkSync8(packageLinkPath);
|
|
116962
117304
|
resolved = realpathSync19(packageLinkPath);
|
|
116963
117305
|
} catch {
|
|
@@ -116980,7 +117322,7 @@ function validateAliasSource(home, name, actual) {
|
|
|
116980
117322
|
}
|
|
116981
117323
|
assertOwnedSafePath(packageRoot, home);
|
|
116982
117324
|
const manifestPath = join66(packageRoot, "package.json");
|
|
116983
|
-
const manifestStat =
|
|
117325
|
+
const manifestStat = lstatSync40(manifestPath), binaryStat = lstatSync40(actual);
|
|
116984
117326
|
if (!manifestStat.isFile() || manifestStat.isSymbolicLink() || !binaryStat.isFile() || binaryStat.isSymbolicLink() || ![0, process.getuid?.() ?? -1].includes(manifestStat.uid) || ![0, process.getuid?.() ?? -1].includes(binaryStat.uid) || manifestStat.mode & 18)
|
|
116985
117327
|
throw new Error("ALIAS_SOURCE_UNSAFE");
|
|
116986
117328
|
const pkg = readPackage(manifestPath);
|
|
@@ -116996,7 +117338,7 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
116996
117338
|
const launcherRuntime = pinnedLauncherRuntime();
|
|
116997
117339
|
pinnedLauncherState(launcherRuntime, currentRuntime, join66(layout.currentPackageRoot, layout.bin.skills ?? "bin/index.js"));
|
|
116998
117340
|
const releaseLock = acquireRuntimeLock(layout.runtimeRoot);
|
|
116999
|
-
const id2 =
|
|
117341
|
+
const id2 = randomUUID11();
|
|
117000
117342
|
const aliases = [];
|
|
117001
117343
|
const receiptDir = join66(currentRuntime, "alias-adoptions");
|
|
117002
117344
|
const receiptPath = join66(receiptDir, `${id2}.json`);
|
|
@@ -117013,7 +117355,7 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
117013
117355
|
if (!entryExists(path))
|
|
117014
117356
|
continue;
|
|
117015
117357
|
assertOwnedSafePath(dir, home, true);
|
|
117016
|
-
const stat3 =
|
|
117358
|
+
const stat3 = lstatSync40(path);
|
|
117017
117359
|
if (stat3.uid !== (process.getuid?.() ?? -1))
|
|
117018
117360
|
throw new Error("ALIAS_LINK_NOT_OWNED");
|
|
117019
117361
|
let launcher;
|
|
@@ -117052,7 +117394,7 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
117052
117394
|
if (!aliases.length)
|
|
117053
117395
|
return { adopted: true, version: layout.currentVersion, aliasCount: 0 };
|
|
117054
117396
|
mkdirSync27(receiptDir, { recursive: true, mode: 448 });
|
|
117055
|
-
const receiptDirStat =
|
|
117397
|
+
const receiptDirStat = lstatSync40(receiptDir);
|
|
117056
117398
|
if (!receiptDirStat.isDirectory() || receiptDirStat.isSymbolicLink() || receiptDirStat.mode & 63)
|
|
117057
117399
|
throw new Error("ALIAS_RECEIPT_DIRECTORY_UNSAFE");
|
|
117058
117400
|
receipt = {
|
|
@@ -117117,9 +117459,9 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
117117
117459
|
if (entryExists(after2))
|
|
117118
117460
|
throw new Error("ALIAS_AFTER_COLLISION");
|
|
117119
117461
|
materializeLauncher(after2, newLauncherState(item));
|
|
117120
|
-
const temp = `${item.path}.skills-alias-rollback-${
|
|
117462
|
+
const temp = `${item.path}.skills-alias-rollback-${randomUUID11()}`;
|
|
117121
117463
|
materializeLauncher(temp, oldLauncherState(item));
|
|
117122
|
-
|
|
117464
|
+
renameSync15(temp, item.path);
|
|
117123
117465
|
if (!launcherIs(item.path, oldLauncherState(item)))
|
|
117124
117466
|
throw new Error("ALIAS_ROLLBACK_READBACK_MISMATCH");
|
|
117125
117467
|
receipt.rollbackCompletedAliases = [...receipt.rollbackCompletedAliases, item.path];
|
|
@@ -117170,7 +117512,7 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
|
|
|
117170
117512
|
const source = validateAliasSource(home, name, item.oldTarget);
|
|
117171
117513
|
if (source.version !== item.oldVersion || source.binarySha256 !== item.oldBinarySha256)
|
|
117172
117514
|
throw new Error("ALIAS_PREIMAGE_DRIFT");
|
|
117173
|
-
const stat3 =
|
|
117515
|
+
const stat3 = lstatSync40(item.path);
|
|
117174
117516
|
if (stat3.uid !== (process.getuid?.() ?? -1))
|
|
117175
117517
|
throw new Error("ALIAS_LINK_DRIFT");
|
|
117176
117518
|
let current;
|
|
@@ -117205,9 +117547,9 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
|
|
|
117205
117547
|
throw new Error("ALIAS_AFTER_DRIFT");
|
|
117206
117548
|
if (launcherTarget(item.path) !== item.newTarget)
|
|
117207
117549
|
throw new Error("ALIAS_TARGET_DRIFT");
|
|
117208
|
-
const temp = `${item.path}.skills-alias-rollback-${
|
|
117550
|
+
const temp = `${item.path}.skills-alias-rollback-${randomUUID11()}`;
|
|
117209
117551
|
materializeLauncher(temp, oldLauncherState(item));
|
|
117210
|
-
|
|
117552
|
+
renameSync15(temp, item.path);
|
|
117211
117553
|
if (!launcherIs(item.path, oldLauncherState(item)))
|
|
117212
117554
|
throw new Error("ALIAS_ROLLBACK_READBACK_MISMATCH");
|
|
117213
117555
|
receipt.rollbackCompletedAliases = [...new Set([...receipt.rollbackCompletedAliases, item.path])];
|
|
@@ -117236,10 +117578,10 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
117236
117578
|
throw new Error("REVIEWED_LOCK_INPUT_PAIR_REQUIRED");
|
|
117237
117579
|
if (!policy)
|
|
117238
117580
|
throw new Error("REVIEWED_LOCK_RELEASE_AGE_REQUIRED");
|
|
117239
|
-
if (!
|
|
117581
|
+
if (!isAbsolute39(options.reviewedLock))
|
|
117240
117582
|
throw new Error("REVIEWED_LOCK_ABSOLUTE_PATH_REQUIRED");
|
|
117241
117583
|
assertNoSymlinkAncestors(dirname40(options.reviewedLock));
|
|
117242
|
-
const stat3 =
|
|
117584
|
+
const stat3 = lstatSync40(options.reviewedLock);
|
|
117243
117585
|
if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.nlink !== 1 || stat3.uid !== process.getuid?.() || stat3.mode & 63 || stat3.size > 8 * 1024 * 1024)
|
|
117244
117586
|
throw new Error("REVIEWED_LOCK_FILE_UNSAFE");
|
|
117245
117587
|
reviewedLockBytes = readFileSync43(options.reviewedLock);
|
|
@@ -117260,10 +117602,10 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
117260
117602
|
throw new Error("REGISTRY_ORIGIN_INVALID");
|
|
117261
117603
|
if (origin.username || origin.password || origin.search || origin.hash)
|
|
117262
117604
|
throw new Error("REGISTRY_ORIGIN_INVALID");
|
|
117263
|
-
const runtimeRootStat =
|
|
117605
|
+
const runtimeRootStat = lstatSync40(layout.runtimeRoot);
|
|
117264
117606
|
if ((runtimeRootStat.mode & 63) !== 0)
|
|
117265
117607
|
throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
|
|
117266
|
-
const id2 =
|
|
117608
|
+
const id2 = randomUUID11();
|
|
117267
117609
|
const stagePath = join66(layout.runtimeRoot, `.stage-${version2}-${id2}`);
|
|
117268
117610
|
const finalPath = join66(layout.runtimeRoot, `${version2}-copyfile`);
|
|
117269
117611
|
const launcherRuntime = pinnedLauncherRuntime();
|
|
@@ -117376,7 +117718,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
117376
117718
|
persistReceipt(join66(stagePath, "rollout-receipt.json"), receipt);
|
|
117377
117719
|
const finalNodeModules = join66(stagePackage, "node_modules");
|
|
117378
117720
|
const stagedNodeModules = join66(stagePath, "node_modules");
|
|
117379
|
-
|
|
117721
|
+
renameSync15(finalNodeModules, stagedNodeModules);
|
|
117380
117722
|
copyFileSync(join66(stagePackage, "package-lock.json"), join66(stagePath, "install-lock.json"));
|
|
117381
117723
|
chmodSync4(join66(stagePath, "install-lock.json"), 384);
|
|
117382
117724
|
const stagedTree = readTree(stagedNodeModules, true);
|
|
@@ -117385,7 +117727,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
117385
117727
|
receipt.targetPackageRoot = join66(finalPath, "node_modules", "@hasna", "skills");
|
|
117386
117728
|
receipt.runtimeTreeSha256 = stagedTree.digest;
|
|
117387
117729
|
persistReceipt(join66(stagePath, "rollout-receipt.json"), receipt);
|
|
117388
|
-
|
|
117730
|
+
renameSync15(stagePath, finalPath);
|
|
117389
117731
|
moved = true;
|
|
117390
117732
|
const finalReceiptBytes = Buffer.from(`${JSON.stringify(receipt, null, 2)}
|
|
117391
117733
|
`);
|
|
@@ -117423,7 +117765,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
117423
117765
|
throw new Error("ROLLBACK_PRESERVATION_PATH_EXISTS");
|
|
117424
117766
|
materializeLauncher(afterPath, newLauncherState(item));
|
|
117425
117767
|
materializeLauncher(temp, oldLauncherState(item));
|
|
117426
|
-
|
|
117768
|
+
renameSync15(temp, item.path);
|
|
117427
117769
|
} catch {
|
|
117428
117770
|
rollbackFailed = true;
|
|
117429
117771
|
}
|
|
@@ -117451,7 +117793,7 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
|
|
|
117451
117793
|
throw new Error("HOME_NOT_FOUND");
|
|
117452
117794
|
const runtimeRoot = join66(realpathSync19(home), ".hasna", "skills", "runtime");
|
|
117453
117795
|
assertNoSymlinkAncestors(runtimeRoot);
|
|
117454
|
-
const rootStat =
|
|
117796
|
+
const rootStat = lstatSync40(runtimeRoot);
|
|
117455
117797
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink() || (rootStat.mode & 63) !== 0)
|
|
117456
117798
|
throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
|
|
117457
117799
|
const releaseLock = acquireRuntimeLock(runtimeRoot);
|
|
@@ -117492,7 +117834,7 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
|
|
|
117492
117834
|
const seen = new Set;
|
|
117493
117835
|
for (const item of receipt.launchers) {
|
|
117494
117836
|
const bin = oldBins[basename21(item.path)];
|
|
117495
|
-
if (!bin || !
|
|
117837
|
+
if (!bin || !isAbsolute39(item.path) || seen.has(item.path) || item.oldTarget !== join66(receipt.currentPackageRoot, bin) || item.newTarget !== join66(receipt.targetPackageRoot, bin) || !/^.+\.skills-prev-[0-9a-f-]{36}$/.test(item.backupPath) || !item.backupPath.startsWith(`${item.path}.skills-prev-`) || typeof item.oldLinkTarget !== "string" || resolve36(dirname40(item.path), item.oldLinkTarget) !== item.oldTarget)
|
|
117496
117838
|
throw new Error("RECEIPT_LAUNCHER_BINDING_INVALID");
|
|
117497
117839
|
assertNoSymlinkAncestors(dirname40(item.path));
|
|
117498
117840
|
assertLauncherRecordShapes(item, launcherProfileForBin(basename21(item.path), bin));
|
|
@@ -117524,9 +117866,9 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
|
|
|
117524
117866
|
const afterPath = `${item.path}.skills-after-${receiptId}`;
|
|
117525
117867
|
if (!entryExists(afterPath))
|
|
117526
117868
|
materializeLauncher(afterPath, newLauncherState(item));
|
|
117527
|
-
const temp = `${item.path}.skills-rollback-${receiptId}-${
|
|
117869
|
+
const temp = `${item.path}.skills-rollback-${receiptId}-${randomUUID11()}`;
|
|
117528
117870
|
materializeLauncher(temp, oldLauncherState(item));
|
|
117529
|
-
|
|
117871
|
+
renameSync15(temp, item.path);
|
|
117530
117872
|
receipt.rollbackCompletedLaunchers = [...new Set([...receipt.rollbackCompletedLaunchers, item.path])];
|
|
117531
117873
|
persistReceipt(receiptPath, receipt);
|
|
117532
117874
|
}
|
|
@@ -117559,9 +117901,9 @@ __export(exports_runtime, {
|
|
|
117559
117901
|
selectedSkillsCommand: () => selectedSkillsCommand,
|
|
117560
117902
|
registerRuntime: () => registerRuntime
|
|
117561
117903
|
});
|
|
117562
|
-
import { createHash as createHash41, randomUUID as
|
|
117563
|
-
import { lstatSync as
|
|
117564
|
-
import { basename as basename22, isAbsolute as
|
|
117904
|
+
import { createHash as createHash41, randomUUID as randomUUID12 } from "crypto";
|
|
117905
|
+
import { lstatSync as lstatSync41, mkdirSync as mkdirSync28, readFileSync as readFileSync44, writeFileSync as writeFileSync25 } from "fs";
|
|
117906
|
+
import { basename as basename22, isAbsolute as isAbsolute40, join as join67 } from "path";
|
|
117565
117907
|
import { createInterface } from "readline";
|
|
117566
117908
|
function registerRuntime(parent) {
|
|
117567
117909
|
parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill; use -- to end Skills options").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--remote", "Run on the configured server, using its catalog and quote", false).option("--target <target>", "Execution target: local or cloud").option("--secret-bindings <path>", "Reviewed, exact-selection local execution vault bindings (JSON file)").option("--secret-bindings-template", "Print a scoped bindings template without resolving secrets or running the skill", false).option("--input <json>", "Structured cloud execution input").option("--skill-version <version>", "Exact selected skill version").option("--selection-profile <id>", "Selected Skills profile").option("--session <id>", "Pinned Skills session").option("--cached", "Use the explicit verified selected cache", false).option("--yes", "Approve the server's quoted credit cost for this run", false).option("--idempotency-key <key>", "Reuse this key when retrying the same remote submission").option("--file <path>", "Attach a local input file to a remote run (repeatable)", (value, prior) => [...prior, value], []).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options, command) => {
|
|
@@ -117629,7 +117971,11 @@ function registerRuntime(parent) {
|
|
|
117629
117971
|
await handleMcp(options);
|
|
117630
117972
|
}));
|
|
117631
117973
|
const setup = parent.command("setup").description("Point this CLI at a Skills API server, or register agent integrations").option("--api-url <url>", "Skills API origin to send remote work to").option("--global", "Accepted for compatibility; the API origin is always per-user", false).option("--json", "Output setup result as JSON", false).action(async (options) => handleSetup(options));
|
|
117632
|
-
setup.command("agents").option("--json", "Output registration result as JSON", false).description("Register the Skills MCP server with all supported agents").action(async (options) => handleMcp({
|
|
117974
|
+
setup.command("agents").option("--json", "Output registration result as JSON", false).description("Register the Skills MCP server with all supported agents").action(async (options, command) => handleMcp({
|
|
117975
|
+
register: "all",
|
|
117976
|
+
json: options.json,
|
|
117977
|
+
apiUrl: command.parent?.opts().apiUrl
|
|
117978
|
+
}));
|
|
117633
117979
|
parent.command("self-update").description("Update @hasna/skills to the latest version").option("--json", "Output result as JSON", false).option("--version <version>", "Install this exact @hasna/skills version as a staged copyfile runtime").option("--min-release-age <days>", "Require a positive integer dependency release age in days for an exact-version update").option("--min-release-age-exclude <pattern>", "Exclude matching package identities from the release-age policy (repeatable)", (pattern, prior) => [...prior, pattern], []).option("--reviewed-lock <path>", "Install from this private absolute package-lock.json path without resolving dependency ranges").option("--reviewed-lock-sha256 <sha256>", "Exact reviewed SHA-256 of the supplied package-lock.json").option("--rollback <receipt-id>", "Restore launcher links from an exact copyfile rollout receipt").option("--adopt-aliases", "Switch verified legacy @hasna/skills aliases to the active copyfile runtime").option("--rollback-aliases <receipt-id>", "Restore aliases from an exact adoption receipt").action(async (options) => {
|
|
117634
117980
|
if ((options.reviewedLock !== undefined || options.reviewedLockSha256 !== undefined) && (!options.version || options.rollback || options.adoptAliases || options.rollbackAliases)) {
|
|
117635
117981
|
console.error(JSON.stringify({ error: "REVIEWED_LOCK_REQUIRES_EXACT_VERSION" }));
|
|
@@ -117760,7 +118106,7 @@ Updating ${name}...
|
|
|
117760
118106
|
async function readUpdatedVersion(bunExecutable) {
|
|
117761
118107
|
const output2 = await readUpdateCommand([bunExecutable, "pm", "bin", "-g"]);
|
|
117762
118108
|
const globalBin = output2.replace(/\r?\n$/, "");
|
|
117763
|
-
if (!globalBin || !
|
|
118109
|
+
if (!globalBin || !isAbsolute40(globalBin) || /[\r\n\0]/.test(globalBin))
|
|
117764
118110
|
throw new Error("Update bin discovery failed");
|
|
117765
118111
|
const installed = Bun.which("skills", { PATH: globalBin, cwd: globalBin });
|
|
117766
118112
|
const selected = Bun.which("skills");
|
|
@@ -118039,7 +118385,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
|
|
|
118039
118385
|
if (!Number.isFinite(timeoutMs) || timeoutMs < 1 || timeoutMs > 1200000 || !Number.isFinite(intervalMs) || intervalMs < 100 || intervalMs > 60000)
|
|
118040
118386
|
throw new Error("Invalid cloud polling bounds");
|
|
118041
118387
|
const client3 = await CloudExecutionClient.configured();
|
|
118042
|
-
const admitted = await client3.submit(slug2, version2, input2, options.idempotencyKey ??
|
|
118388
|
+
const admitted = await client3.submit(slug2, version2, input2, options.idempotencyKey ?? randomUUID12(), selected?.selection);
|
|
118043
118389
|
if (options.wait)
|
|
118044
118390
|
console.error(JSON.stringify({ executionId: admitted.id, status: admitted.status }));
|
|
118045
118391
|
const result3 = options.wait ? await client3.wait(admitted.id, { timeoutMs, intervalMs }) : admitted;
|
|
@@ -118096,7 +118442,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
|
|
|
118096
118442
|
try {
|
|
118097
118443
|
parsePollingOptions(options);
|
|
118098
118444
|
inputFiles = (options.file ?? []).map((path) => {
|
|
118099
|
-
const info =
|
|
118445
|
+
const info = lstatSync41(path);
|
|
118100
118446
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
118101
118447
|
throw new Error("Input must be a regular file no larger than 20 MiB");
|
|
118102
118448
|
return { name: basename22(path), bytes: new Uint8Array(readFileSync44(path)) };
|
|
@@ -118526,7 +118872,7 @@ function ensureSafeExportParent(root2, relativePath) {
|
|
|
118526
118872
|
if (part)
|
|
118527
118873
|
parent = join67(parent, part);
|
|
118528
118874
|
try {
|
|
118529
|
-
if (!
|
|
118875
|
+
if (!lstatSync41(parent).isDirectory() || lstatSync41(parent).isSymbolicLink())
|
|
118530
118876
|
throw new Error("Unsafe artifact directory");
|
|
118531
118877
|
} catch (error61) {
|
|
118532
118878
|
if (error61.code !== "ENOENT")
|
|
@@ -118821,7 +119167,7 @@ var exports_recurring = {};
|
|
|
118821
119167
|
__export(exports_recurring, {
|
|
118822
119168
|
registerRecurringCommands: () => registerRecurringCommands
|
|
118823
119169
|
});
|
|
118824
|
-
import { constants as constants28, closeSync as closeSync29, fstatSync as fstatSync29, lstatSync as
|
|
119170
|
+
import { constants as constants28, closeSync as closeSync29, fstatSync as fstatSync29, lstatSync as lstatSync42, openSync as openSync29, readSync as readSync21 } from "fs";
|
|
118825
119171
|
import { createInterface as createInterface2 } from "readline";
|
|
118826
119172
|
function readRequest(path) {
|
|
118827
119173
|
const fd = openSync29(path, constants28.O_RDONLY | constants28.O_NOFOLLOW | constants28.O_NONBLOCK);
|
|
@@ -118837,7 +119183,7 @@ function readRequest(path) {
|
|
|
118837
119183
|
break;
|
|
118838
119184
|
length += n2;
|
|
118839
119185
|
}
|
|
118840
|
-
const after2 = fstatSync29(fd), current =
|
|
119186
|
+
const after2 = fstatSync29(fd), current = lstatSync42(path);
|
|
118841
119187
|
if (length !== before2.size || after2.size !== before2.size || before2.mtimeMs !== after2.mtimeMs || before2.ctimeMs !== after2.ctimeMs || current.dev !== before2.dev || current.ino !== before2.ino || !current.isFile() || current.isSymbolicLink())
|
|
118842
119188
|
throw new RecurringInputError;
|
|
118843
119189
|
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
|
|
@@ -119121,7 +119467,7 @@ var init_completion = __esm(() => {
|
|
|
119121
119467
|
});
|
|
119122
119468
|
|
|
119123
119469
|
// src/lib/portable-snapshot-filter.ts
|
|
119124
|
-
import { readdirSync as readdirSync25, statSync as
|
|
119470
|
+
import { readdirSync as readdirSync25, statSync as statSync23 } from "fs";
|
|
119125
119471
|
import { homedir as homedir11 } from "os";
|
|
119126
119472
|
import { join as join68, sep as sep19 } from "path";
|
|
119127
119473
|
function isExcludedSkillFileName(fileName) {
|
|
@@ -119189,7 +119535,7 @@ function walkEntries(absoluteRoot) {
|
|
|
119189
119535
|
}
|
|
119190
119536
|
function isRegularFile(filePath) {
|
|
119191
119537
|
try {
|
|
119192
|
-
return
|
|
119538
|
+
return statSync23(filePath).isFile();
|
|
119193
119539
|
} catch {
|
|
119194
119540
|
return false;
|
|
119195
119541
|
}
|
|
@@ -119275,10 +119621,10 @@ import {
|
|
|
119275
119621
|
copyFileSync as copyFileSync2,
|
|
119276
119622
|
mkdirSync as mkdirSync29,
|
|
119277
119623
|
readFileSync as readFileSync45,
|
|
119278
|
-
statSync as
|
|
119624
|
+
statSync as statSync24,
|
|
119279
119625
|
writeFileSync as writeFileSync26
|
|
119280
119626
|
} from "fs";
|
|
119281
|
-
import { dirname as dirname42, isAbsolute as
|
|
119627
|
+
import { dirname as dirname42, isAbsolute as isAbsolute41, relative as relative14, resolve as resolve37, sep as sep20 } from "path";
|
|
119282
119628
|
function validateStationId(stationId) {
|
|
119283
119629
|
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
119284
119630
|
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
@@ -119315,7 +119661,7 @@ function scanHome(definition, homesRoot) {
|
|
|
119315
119661
|
skipped.push({ relativePath: entry.relativePath, reason: "not-regular-file" });
|
|
119316
119662
|
continue;
|
|
119317
119663
|
}
|
|
119318
|
-
const info =
|
|
119664
|
+
const info = statSync24(entry.fullPath);
|
|
119319
119665
|
portable.push({
|
|
119320
119666
|
relativePath: entry.relativePath,
|
|
119321
119667
|
fullPath: entry.fullPath,
|
|
@@ -119384,7 +119730,7 @@ function writeStationSnapshot(options) {
|
|
|
119384
119730
|
for (const plan of plans) {
|
|
119385
119731
|
const destination = resolve37(repoRoot, plan.destination);
|
|
119386
119732
|
const destinationRelative = relative14(repoRoot, destination);
|
|
119387
|
-
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep20) ||
|
|
119733
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep20) || isAbsolute41(destinationRelative)) {
|
|
119388
119734
|
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
119389
119735
|
}
|
|
119390
119736
|
let existingDigest = null;
|
|
@@ -119857,7 +120203,7 @@ var init_create_sync_config = __esm(() => {
|
|
|
119857
120203
|
});
|
|
119858
120204
|
|
|
119859
120205
|
// src/lib/agent-install-selection.ts
|
|
119860
|
-
import { lstatSync as
|
|
120206
|
+
import { lstatSync as lstatSync43 } from "fs";
|
|
119861
120207
|
import { dirname as dirname43, join as join70, resolve as resolve38 } from "path";
|
|
119862
120208
|
import { homedir as homedir12 } from "os";
|
|
119863
120209
|
function detectedIntegrationAgents(options = {}) {
|
|
@@ -119871,7 +120217,7 @@ function detectedIntegrationAgents(options = {}) {
|
|
|
119871
120217
|
throw new Error("Invalid existing bridge agent inventory");
|
|
119872
120218
|
const present2 = (path) => {
|
|
119873
120219
|
try {
|
|
119874
|
-
return
|
|
120220
|
+
return lstatSync43(path, { throwIfNoEntry: false }) !== undefined;
|
|
119875
120221
|
} catch {
|
|
119876
120222
|
throw new Error("Agent presence cannot be inspected; review native configuration before hook installation");
|
|
119877
120223
|
}
|
|
@@ -119901,7 +120247,7 @@ var init_agent_install_selection = __esm(() => {
|
|
|
119901
120247
|
});
|
|
119902
120248
|
|
|
119903
120249
|
// src/lib/codex-native-config.ts
|
|
119904
|
-
import { isDeepStrictEqual as
|
|
120250
|
+
import { isDeepStrictEqual as isDeepStrictEqual17 } from "util";
|
|
119905
120251
|
function isRecord8(value) {
|
|
119906
120252
|
if (!value || typeof value !== "object")
|
|
119907
120253
|
return false;
|
|
@@ -119923,7 +120269,7 @@ function decimalIdentity(text4) {
|
|
|
119923
120269
|
return `${match[1]}${coefficient}e${exponent}`;
|
|
119924
120270
|
}
|
|
119925
120271
|
function codexNativeConfigEqual(native, expected) {
|
|
119926
|
-
if (
|
|
120272
|
+
if (isDeepStrictEqual17(native, expected))
|
|
119927
120273
|
return true;
|
|
119928
120274
|
if (typeof expected === "number") {
|
|
119929
120275
|
if (!Number.isFinite(expected) || !isRecord8(native))
|
|
@@ -119947,11 +120293,11 @@ var NUMBER_TAG = "$serde_json::private::Number";
|
|
|
119947
120293
|
var init_codex_native_config = () => {};
|
|
119948
120294
|
|
|
119949
120295
|
// src/lib/codex-hook-trust-identity.ts
|
|
119950
|
-
import { lstatSync as
|
|
119951
|
-
import { dirname as dirname44, isAbsolute as
|
|
119952
|
-
import { isDeepStrictEqual as
|
|
120296
|
+
import { lstatSync as lstatSync44, realpathSync as realpathSync20 } from "fs";
|
|
120297
|
+
import { dirname as dirname44, isAbsolute as isAbsolute42, join as join71, resolve as resolve39 } from "path";
|
|
120298
|
+
import { isDeepStrictEqual as isDeepStrictEqual18 } from "util";
|
|
119953
120299
|
function commandPhysical(command) {
|
|
119954
|
-
need8(typeof command === "string" &&
|
|
120300
|
+
need8(typeof command === "string" && isAbsolute42(command) && !command.includes("\x00") && resolve39(command) === command, COMMAND_NOT_CANONICAL);
|
|
119955
120301
|
const physical = realpathSync20(command);
|
|
119956
120302
|
let spelled;
|
|
119957
120303
|
try {
|
|
@@ -119962,7 +120308,7 @@ function commandPhysical(command) {
|
|
|
119962
120308
|
safeParents(spelled);
|
|
119963
120309
|
let direct = false;
|
|
119964
120310
|
try {
|
|
119965
|
-
const leaf =
|
|
120311
|
+
const leaf = lstatSync44(spelled);
|
|
119966
120312
|
direct = leaf.isSymbolicLink() ? trustedAncestorOwner(leaf.uid) && directAliasTarget(spelled) === physical : spelled === physical;
|
|
119967
120313
|
} catch {}
|
|
119968
120314
|
need8(direct, COMMAND_ALIAS_UNSAFE);
|
|
@@ -120006,7 +120352,7 @@ function targetUnchanged(command, target) {
|
|
|
120006
120352
|
assertPinnedRuntime(target.runtime);
|
|
120007
120353
|
}
|
|
120008
120354
|
function inspectRecordedSkillsCli(command, expected) {
|
|
120009
|
-
need8(
|
|
120355
|
+
need8(isAbsolute42(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
|
|
120010
120356
|
const target = skillsCommandTarget(command), resolved = target.entry;
|
|
120011
120357
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
120012
120358
|
const manifest = snapshot(join71(dirname44(dirname44(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
@@ -120014,7 +120360,7 @@ function inspectRecordedSkillsCli(command, expected) {
|
|
|
120014
120360
|
need8(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join71(dirname44(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
120015
120361
|
need8((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
120016
120362
|
const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
|
|
120017
|
-
need8(
|
|
120363
|
+
need8(isDeepStrictEqual18(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
120018
120364
|
return { receipt, recheck() {
|
|
120019
120365
|
targetUnchanged(command, target);
|
|
120020
120366
|
unchanged2(cli);
|
|
@@ -120025,7 +120371,7 @@ function bindSkillsCli(command, reviewed) {
|
|
|
120025
120371
|
const normal = Bun.which("skills", { PATH: process.env.PATH });
|
|
120026
120372
|
need8(normal, "SKILLS_COMMAND_UNAVAILABLE");
|
|
120027
120373
|
const normalTarget = skillsCommandTarget(normal), resolved = normalTarget.entry;
|
|
120028
|
-
const bound =
|
|
120374
|
+
const bound = isAbsolute42(command) ? command : command === "skills" ? normal : undefined;
|
|
120029
120375
|
need8(bound, "SKILLS_COMMAND_MISMATCH");
|
|
120030
120376
|
const boundTarget = skillsCommandTarget(bound);
|
|
120031
120377
|
need8(boundTarget.entry === resolved, "SKILLS_COMMAND_MISMATCH");
|
|
@@ -120084,19 +120430,19 @@ var init_codex_hook_trust_identity = __esm(() => {
|
|
|
120084
120430
|
});
|
|
120085
120431
|
|
|
120086
120432
|
// src/lib/codex-hook-policy-recovery.ts
|
|
120087
|
-
import { isDeepStrictEqual as
|
|
120433
|
+
import { isDeepStrictEqual as isDeepStrictEqual19 } from "util";
|
|
120088
120434
|
function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
|
|
120089
120435
|
need8(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
|
|
120090
120436
|
need8(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
120091
120437
|
const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
|
|
120092
120438
|
const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
|
|
120093
120439
|
need8(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
|
|
120094
|
-
const changes = ["roots", "sources"].filter((key2) => !
|
|
120440
|
+
const changes = ["roots", "sources"].filter((key2) => !isDeepStrictEqual19(oldDiscovery[key2], newDiscovery[key2])).map((key2) => ({ path: `bridge.discovery.claude.${key2}`, before: oldDiscovery[key2], after: newDiscovery[key2] }));
|
|
120095
120441
|
need8(changes.length > 0, "RECONCILE_POLICY_CHANGED");
|
|
120096
120442
|
const compared = structuredClone(current);
|
|
120097
120443
|
compared.bridge.discovery.claude.roots = oldDiscovery.roots;
|
|
120098
120444
|
compared.bridge.discovery.claude.sources = oldDiscovery.sources;
|
|
120099
|
-
need8(
|
|
120445
|
+
need8(isDeepStrictEqual19(before2, compared), "RECONCILE_POLICY_CHANGED");
|
|
120100
120446
|
verifyAgentDiscovery(newDiscovery);
|
|
120101
120447
|
return { reason: options.reason, changes };
|
|
120102
120448
|
}
|
|
@@ -120107,16 +120453,16 @@ var init_codex_hook_policy_recovery = __esm(() => {
|
|
|
120107
120453
|
});
|
|
120108
120454
|
|
|
120109
120455
|
// src/lib/agent-codex-trust.ts
|
|
120110
|
-
import { lstatSync as
|
|
120111
|
-
import { createHash as createHash43, randomUUID as
|
|
120456
|
+
import { lstatSync as lstatSync45, mkdirSync as mkdirSync30, readdirSync as readdirSync26, readFileSync as readFileSync46, realpathSync as realpathSync21, statSync as statSync25 } from "fs";
|
|
120457
|
+
import { createHash as createHash43, randomUUID as randomUUID13 } from "crypto";
|
|
120112
120458
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
120113
|
-
import { dirname as dirname45, isAbsolute as
|
|
120459
|
+
import { dirname as dirname45, isAbsolute as isAbsolute43, join as join72, resolve as resolve40 } from "path";
|
|
120114
120460
|
import { homedir as homedir13 } from "os";
|
|
120115
|
-
import { isDeepStrictEqual as
|
|
120461
|
+
import { isDeepStrictEqual as isDeepStrictEqual20 } from "util";
|
|
120116
120462
|
function verifyReleaseArtifact(proof, skillsCli) {
|
|
120117
|
-
need8(
|
|
120463
|
+
need8(isAbsolute43(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
120118
120464
|
const tarPath = realpathSync21(proof.packageTarPath);
|
|
120119
|
-
need8(
|
|
120465
|
+
need8(statSync25(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
120120
120466
|
const tarBytes = readFileSync46(tarPath);
|
|
120121
120467
|
need8(tarBytes.byteLength === proof.packageTarBytes && createHash43("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
|
|
120122
120468
|
const packageRoot = dirname45(dirname45(realpathSync21(skillsCli.receipt.path)));
|
|
@@ -120140,10 +120486,10 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120140
120486
|
const home = resolve40(options.home ?? homedir13()), dataDir3 = resolve40(options.dataDir ?? getDataDirReadOnly());
|
|
120141
120487
|
const parent = resolve40(join72(dataDir3, "native-hook-trust")), journal = resolve40(options.journal);
|
|
120142
120488
|
need8(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
|
|
120143
|
-
const dir =
|
|
120489
|
+
const dir = lstatSync45(journal, { throwIfNoEntry: false });
|
|
120144
120490
|
need8(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
|
|
120145
|
-
need8(!
|
|
120146
|
-
need8(
|
|
120491
|
+
need8(!lstatSync45(join72(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
|
|
120492
|
+
need8(lstatSync45(join72(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
|
|
120147
120493
|
const stoppedFile = snapshot(join72(journal, "stopped.json"), true);
|
|
120148
120494
|
const intentFile = snapshot(join72(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
|
|
120149
120495
|
const configBefore = snapshot(join72(journal, "config.before.toml"), true), hooksBefore = snapshot(join72(journal, "hooks.before.json"), true), policyBefore = snapshot(join72(journal, "policy.before.json"), true);
|
|
@@ -120154,7 +120500,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120154
120500
|
const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
|
|
120155
120501
|
const digestInput = { version: 1, home: intent.home ?? home, configPath: intent.configPath, ...intent.nativeConfigPath !== undefined ? { nativeConfigPath: intent.nativeConfigPath } : {}, configSha256, configVersion, policySha256: intent.policySha256, hooksSha256: intent.hooksSha256, skillsCli: intent.skillsCli, nativeVersion: intent.nativeVersion, declarations, admitted };
|
|
120156
120502
|
need8(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
|
|
120157
|
-
need8(
|
|
120503
|
+
need8(isDeepStrictEqual20(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
|
|
120158
120504
|
need8(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
|
|
120159
120505
|
const policyCurrent = snapshot(join72(dataDir3, "agent-policy.json"), true);
|
|
120160
120506
|
const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
|
|
@@ -120167,13 +120513,13 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120167
120513
|
if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
|
|
120168
120514
|
need8(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
|
|
120169
120515
|
const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
|
|
120170
|
-
need8(
|
|
120516
|
+
need8(isDeepStrictEqual20(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
|
|
120171
120517
|
supersededBinding = true;
|
|
120172
120518
|
}
|
|
120173
120519
|
if (supersededBinding || recovery) {
|
|
120174
120520
|
need8(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
|
|
120175
120521
|
const proof = options.releaseProof;
|
|
120176
|
-
need8(!!proof &&
|
|
120522
|
+
need8(!!proof && isAbsolute43(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
|
|
120177
120523
|
}
|
|
120178
120524
|
const currentConfig = snapshot(intent.configPath, true);
|
|
120179
120525
|
const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
|
|
@@ -120203,7 +120549,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120203
120549
|
need8(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
|
|
120204
120550
|
}
|
|
120205
120551
|
} else
|
|
120206
|
-
need8(
|
|
120552
|
+
need8(isDeepStrictEqual20(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
|
|
120207
120553
|
const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
|
|
120208
120554
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
|
|
120209
120555
|
const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
|
|
@@ -120212,14 +120558,14 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120212
120558
|
const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
120213
120559
|
if (supersededBinding)
|
|
120214
120560
|
verifyReleaseArtifact(options.releaseProof, skillsCli);
|
|
120215
|
-
const skillsBindingChanged = !
|
|
120561
|
+
const skillsBindingChanged = !isDeepStrictEqual20(skillsCli.receipt, intent.skillsCli);
|
|
120216
120562
|
need8(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
120217
120563
|
if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
|
|
120218
120564
|
need8(supersededBinding, "RECONCILE_HOOKS_CHANGED");
|
|
120219
120565
|
const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
|
|
120220
120566
|
for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
|
|
120221
120567
|
const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
|
|
120222
|
-
need8(
|
|
120568
|
+
need8(isDeepStrictEqual20(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
|
|
120223
120569
|
}
|
|
120224
120570
|
}
|
|
120225
120571
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
@@ -120242,9 +120588,9 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120242
120588
|
delete identity6.command;
|
|
120243
120589
|
return identity6;
|
|
120244
120590
|
};
|
|
120245
|
-
need8(
|
|
120591
|
+
need8(isDeepStrictEqual20(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
120246
120592
|
if (!plannedKeys.has(expected.key))
|
|
120247
|
-
need8(
|
|
120593
|
+
need8(isDeepStrictEqual20(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
|
|
120248
120594
|
}
|
|
120249
120595
|
for (const wanted of intent.hooks) {
|
|
120250
120596
|
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join72(home, ".codex/hooks.json"), hooksPath));
|
|
@@ -120263,7 +120609,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120263
120609
|
const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
120264
120610
|
need8(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
|
|
120265
120611
|
const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
|
|
120266
|
-
need8(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks ||
|
|
120612
|
+
need8(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual20(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
|
|
120267
120613
|
const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
120268
120614
|
const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
120269
120615
|
need8(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
|
|
@@ -120318,7 +120664,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
120318
120664
|
const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
|
|
120319
120665
|
const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
120320
120666
|
const physicalRoot = alias?.target ?? join72(home, ".codex"), hooksPath = join72(physicalRoot, "hooks.json"), configPath = join72(physicalRoot, "config.toml");
|
|
120321
|
-
need8(options.codexHome === undefined ||
|
|
120667
|
+
need8(options.codexHome === undefined || isAbsolute43(options.codexHome) && [join72(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
|
|
120322
120668
|
const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
|
|
120323
120669
|
const nativeConfigPath = join72(codexHome ?? join72(home, ".codex"), "config.toml");
|
|
120324
120670
|
const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
|
|
@@ -120328,7 +120674,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
120328
120674
|
const groups = declarations[event];
|
|
120329
120675
|
need8(Array.isArray(groups), "DECLARATION_CHANGED");
|
|
120330
120676
|
const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
|
|
120331
|
-
need8(matches2.length === 1 &&
|
|
120677
|
+
need8(matches2.length === 1 && isDeepStrictEqual20(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
|
|
120332
120678
|
expected.push({ event: nativeEvent, key: `${join72(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
|
|
120333
120679
|
}
|
|
120334
120680
|
codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
|
|
@@ -120374,27 +120720,27 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
120374
120720
|
if (options.apply)
|
|
120375
120721
|
need8(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
|
|
120376
120722
|
const parent = join72(dataDir3, "native-hook-trust");
|
|
120377
|
-
const st =
|
|
120723
|
+
const st = lstatSync45(parent, { throwIfNoEntry: false });
|
|
120378
120724
|
if (st) {
|
|
120379
120725
|
need8(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
|
|
120380
120726
|
const priorJournals = readdirSync26(parent);
|
|
120381
120727
|
need8(priorJournals.length < 1000, "JOURNAL_BOUND");
|
|
120382
120728
|
for (const name of priorJournals) {
|
|
120383
120729
|
need8(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
|
|
120384
|
-
need8(
|
|
120730
|
+
need8(lstatSync45(join72(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
|
|
120385
120731
|
}
|
|
120386
120732
|
}
|
|
120387
120733
|
if (!options.apply || !planned.length)
|
|
120388
120734
|
return baseReceipt;
|
|
120389
120735
|
if (!st)
|
|
120390
120736
|
mkdirSync30(parent, { mode: 448 });
|
|
120391
|
-
journal = join72(parent,
|
|
120737
|
+
journal = join72(parent, randomUUID13());
|
|
120392
120738
|
mkdirSync30(journal, { mode: 448 });
|
|
120393
120739
|
save(join72(journal, "config.before.toml"), configFile.bytes);
|
|
120394
120740
|
save(join72(journal, "hooks.before.json"), hooksFile.bytes);
|
|
120395
120741
|
save(join72(journal, "policy.before.json"), policyFile.bytes);
|
|
120396
120742
|
save(join72(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook), ...codexAdmissionReceipt(admission) }));
|
|
120397
|
-
need8(
|
|
120743
|
+
need8(isDeepStrictEqual20(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
|
|
120398
120744
|
checkInputs();
|
|
120399
120745
|
let result2;
|
|
120400
120746
|
try {
|
|
@@ -120408,7 +120754,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
120408
120754
|
expectedConfig.hooks.state ??= {};
|
|
120409
120755
|
for (const h of planned)
|
|
120410
120756
|
expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
|
|
120411
|
-
need8(
|
|
120757
|
+
need8(isDeepStrictEqual20(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys4) === preservationText, "PRESERVATION_FAILED");
|
|
120412
120758
|
const savedConfig = snapshot(join72(journal, "config.before.toml"), true);
|
|
120413
120759
|
need8(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
|
|
120414
120760
|
const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
|
|
@@ -120416,8 +120762,8 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
120416
120762
|
unchanged2(hooksFile);
|
|
120417
120763
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
|
|
120418
120764
|
const current = await list2(), confirmed = admit(current);
|
|
120419
|
-
need8(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") &&
|
|
120420
|
-
need8(
|
|
120765
|
+
need8(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual20(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
|
|
120766
|
+
need8(isDeepStrictEqual20(current.filter((h) => !keys4.includes(h.key)), discovered.filter((h) => !keys4.includes(h.key))), "UNRELATED_HOOK_CHANGED");
|
|
120421
120767
|
unchanged2(after2);
|
|
120422
120768
|
unchanged2(savedConfig);
|
|
120423
120769
|
unchanged2(hooksFile);
|
|
@@ -120550,9 +120896,9 @@ var init_codex_native_trust = __esm(() => {
|
|
|
120550
120896
|
|
|
120551
120897
|
// src/lib/claude-prospective-review.ts
|
|
120552
120898
|
import { createHash as createHash45 } from "crypto";
|
|
120553
|
-
import { lstatSync as
|
|
120554
|
-
import { basename as basename23, dirname as dirname46, isAbsolute as
|
|
120555
|
-
import { isDeepStrictEqual as
|
|
120899
|
+
import { lstatSync as lstatSync46, readFileSync as readFileSync48, readdirSync as readdirSync27, realpathSync as realpathSync22 } from "fs";
|
|
120900
|
+
import { basename as basename23, dirname as dirname46, isAbsolute as isAbsolute44, join as join74, relative as relative15, resolve as resolve42, sep as sep21 } from "path";
|
|
120901
|
+
import { isDeepStrictEqual as isDeepStrictEqual21 } from "util";
|
|
120556
120902
|
function hashClaudeDiscoveryBinding(binding) {
|
|
120557
120903
|
return sha8(JSON.stringify(binding));
|
|
120558
120904
|
}
|
|
@@ -120602,7 +120948,7 @@ function keys4(value, expected, name) {
|
|
|
120602
120948
|
refuse8(`${name} has an unsupported shape`);
|
|
120603
120949
|
}
|
|
120604
120950
|
function abs(path, name) {
|
|
120605
|
-
if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !
|
|
120951
|
+
if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !isAbsolute44(path) || resolve42(path) !== path)
|
|
120606
120952
|
refuse8(`${name} must be a normalized absolute path`);
|
|
120607
120953
|
}
|
|
120608
120954
|
function validUtcTimestamp(value) {
|
|
@@ -120611,23 +120957,23 @@ function validUtcTimestamp(value) {
|
|
|
120611
120957
|
function safeFile(path, name) {
|
|
120612
120958
|
abs(path, name);
|
|
120613
120959
|
for (let at2 = dirname46(path);; at2 = dirname46(at2)) {
|
|
120614
|
-
const stat4 =
|
|
120960
|
+
const stat4 = lstatSync46(at2, { throwIfNoEntry: false });
|
|
120615
120961
|
if (!stat4?.isDirectory() || stat4.isSymbolicLink())
|
|
120616
120962
|
refuse8(`${name} traverses a symlink or non-directory`);
|
|
120617
120963
|
if (at2 === dirname46(at2))
|
|
120618
120964
|
break;
|
|
120619
120965
|
}
|
|
120620
|
-
const stat3 =
|
|
120966
|
+
const stat3 = lstatSync46(path, { throwIfNoEntry: false });
|
|
120621
120967
|
if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > MAX_CANDIDATE_BYTES)
|
|
120622
120968
|
refuse8(`${name} is not a bounded regular file`);
|
|
120623
120969
|
return readFileSync48(path);
|
|
120624
120970
|
}
|
|
120625
120971
|
function canonicalDir(path, name) {
|
|
120626
120972
|
abs(path, name);
|
|
120627
|
-
if (realpathSync22(path) !== path || !
|
|
120973
|
+
if (realpathSync22(path) !== path || !lstatSync46(path).isDirectory())
|
|
120628
120974
|
refuse8(`${name} is not a canonical directory`);
|
|
120629
120975
|
for (let at2 = path;; at2 = dirname46(at2)) {
|
|
120630
|
-
const stat3 =
|
|
120976
|
+
const stat3 = lstatSync46(at2);
|
|
120631
120977
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
120632
120978
|
refuse8(`${name} traverses a symlink`);
|
|
120633
120979
|
if (at2 === dirname46(at2))
|
|
@@ -120639,7 +120985,7 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
120639
120985
|
const entries = [];
|
|
120640
120986
|
let bytes = 0;
|
|
120641
120987
|
const walk2 = (directory3) => {
|
|
120642
|
-
const beforeDirectory =
|
|
120988
|
+
const beforeDirectory = lstatSync46(directory3);
|
|
120643
120989
|
const names = readdirSync27(directory3).sort();
|
|
120644
120990
|
if (new Set(names).size !== names.length)
|
|
120645
120991
|
refuse8("candidate contains ambiguous directory entries");
|
|
@@ -120649,7 +120995,7 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
120649
120995
|
const path = join74(directory3, name), rel = relative15(root2, path).split(sep21).join("/");
|
|
120650
120996
|
if (entries.length >= MAX_CANDIDATE_FILES)
|
|
120651
120997
|
refuse8("candidate closure exceeds its member limit");
|
|
120652
|
-
const stat3 =
|
|
120998
|
+
const stat3 = lstatSync46(path);
|
|
120653
120999
|
if (stat3.isSymbolicLink())
|
|
120654
121000
|
refuse8("candidate closure contains a symlink");
|
|
120655
121001
|
if (stat3.isDirectory()) {
|
|
@@ -120659,14 +121005,14 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
120659
121005
|
bytes += stat3.size;
|
|
120660
121006
|
if (bytes > MAX_CANDIDATE_BYTES)
|
|
120661
121007
|
refuse8("candidate closure exceeds its byte limit");
|
|
120662
|
-
const content = safeFile(path, "candidate member"), after2 =
|
|
121008
|
+
const content = safeFile(path, "candidate member"), after2 = lstatSync46(path);
|
|
120663
121009
|
if (!after2.isFile() || after2.dev !== stat3.dev || after2.ino !== stat3.ino || after2.size !== stat3.size || after2.mtimeMs !== stat3.mtimeMs || after2.ctimeMs !== stat3.ctimeMs)
|
|
120664
121010
|
refuse8("candidate member changed while being read");
|
|
120665
121011
|
entries.push([rel, "file", sha8(content)]);
|
|
120666
121012
|
} else
|
|
120667
121013
|
refuse8("candidate closure contains a special file");
|
|
120668
121014
|
}
|
|
120669
|
-
const afterDirectory =
|
|
121015
|
+
const afterDirectory = lstatSync46(directory3);
|
|
120670
121016
|
if (!afterDirectory.isDirectory() || afterDirectory.dev !== beforeDirectory.dev || afterDirectory.ino !== beforeDirectory.ino || afterDirectory.mtimeMs !== beforeDirectory.mtimeMs || afterDirectory.ctimeMs !== beforeDirectory.ctimeMs)
|
|
120671
121017
|
refuse8("candidate directory changed while being read");
|
|
120672
121018
|
};
|
|
@@ -120690,11 +121036,11 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
|
|
|
120690
121036
|
if (names.has(row2.name))
|
|
120691
121037
|
refuse8("candidate catalog repeats a plugin name");
|
|
120692
121038
|
names.add(row2.name);
|
|
120693
|
-
if (typeof row2.source !== "string" ||
|
|
121039
|
+
if (typeof row2.source !== "string" || isAbsolute44(row2.source) || /[\\\x00-\x1f\x7f]/.test(row2.source))
|
|
120694
121040
|
refuse8("candidate catalog plugin source is invalid");
|
|
120695
121041
|
const pluginRoot = resolve42(root2, row2.source);
|
|
120696
121042
|
const relativeRoot = relative15(root2, pluginRoot);
|
|
120697
|
-
if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep21}`) ||
|
|
121043
|
+
if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep21}`) || isAbsolute44(relativeRoot))
|
|
120698
121044
|
refuse8("candidate plugin source escapes the candidate root");
|
|
120699
121045
|
const path = join74(pluginRoot, ".claude-plugin/plugin.json");
|
|
120700
121046
|
return { plugin: row2.name, ...captureClaudePluginManifestFile(path) };
|
|
@@ -120713,7 +121059,7 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
|
|
|
120713
121059
|
}
|
|
120714
121060
|
function readWitness(path, expected, name) {
|
|
120715
121061
|
abs(path, `${name} path`);
|
|
120716
|
-
const stat3 =
|
|
121062
|
+
const stat3 = lstatSync46(path, { throwIfNoEntry: false });
|
|
120717
121063
|
if (expected === null) {
|
|
120718
121064
|
if (stat3)
|
|
120719
121065
|
refuse8(`${name} was absent at review but is now present`);
|
|
@@ -120765,7 +121111,7 @@ function unreviewedProjectSettingsRefusal(path, expected, name) {
|
|
|
120765
121111
|
return null;
|
|
120766
121112
|
}
|
|
120767
121113
|
function jsonFile(path, name) {
|
|
120768
|
-
const stat3 =
|
|
121114
|
+
const stat3 = lstatSync46(path, { throwIfNoEntry: false });
|
|
120769
121115
|
if (!stat3)
|
|
120770
121116
|
return null;
|
|
120771
121117
|
let value;
|
|
@@ -120797,7 +121143,7 @@ function assertNoUnprojectedSkillPayload(root2, catalogPath, marketplace, plugin
|
|
|
120797
121143
|
const walk2 = (directory3) => {
|
|
120798
121144
|
for (const name of readdirSync27(directory3).sort()) {
|
|
120799
121145
|
const path = join74(directory3, name), rel = relative15(root2, path).split(sep21).join("/");
|
|
120800
|
-
const stat3 =
|
|
121146
|
+
const stat3 = lstatSync46(path);
|
|
120801
121147
|
if (stat3.isDirectory())
|
|
120802
121148
|
walk2(path);
|
|
120803
121149
|
else if (stat3.isFile()) {
|
|
@@ -120863,7 +121209,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
120863
121209
|
refuse8("CLAUDE_CODE_PLUGIN_CACHE_DIR overrides are unsupported by this prospective schema; bind and review the actual cache root first");
|
|
120864
121210
|
if (request2.native.pluginRoot !== pluginRoot)
|
|
120865
121211
|
refuse8("Claude plugin root differs from the supported standard plugins directory; Cowork and custom cache roots require a separately bound schema");
|
|
120866
|
-
const pluginRootStat =
|
|
121212
|
+
const pluginRootStat = lstatSync46(pluginRoot, { throwIfNoEntry: false });
|
|
120867
121213
|
if (pluginRootStat && (!pluginRootStat.isDirectory() || pluginRootStat.isSymbolicLink()))
|
|
120868
121214
|
refuse8("Claude plugin root is not a regular directory");
|
|
120869
121215
|
keys4(request2.candidate, ["marketplace", "root", "catalogPath", "catalogSha256", "closureSha256", "plugins", ...hasOwn2(request2.candidate, "releaseManifest") ? ["releaseManifest"] : [], ...hasOwn2(request2.candidate, "functionHooksEnv") ? ["functionHooksEnv"] : [], ...hasOwn2(request2.candidate, "settingsMarketplaceSource") ? ["settingsMarketplaceSource"] : []], "candidate");
|
|
@@ -120929,7 +121275,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
120929
121275
|
refuse8("plugin manifest must be under a plugin root inside the frozen marketplace closure");
|
|
120930
121276
|
const pluginRoot2 = dirname46(dirname46(selected.manifestPath));
|
|
120931
121277
|
const relativePluginRoot = relative15(candidate2.root, pluginRoot2);
|
|
120932
|
-
if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep21}`) ||
|
|
121278
|
+
if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep21}`) || isAbsolute44(relativePluginRoot))
|
|
120933
121279
|
refuse8("plugin root must be a child of the frozen marketplace root");
|
|
120934
121280
|
canonicalDir(pluginRoot2, "candidate plugin root");
|
|
120935
121281
|
if (!SHA256.test(selected.manifestSha256))
|
|
@@ -120963,7 +121309,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
120963
121309
|
const sourcePath = selectedEntry.source;
|
|
120964
121310
|
const sourceRelativePath = relative15(candidate2.root, pluginRoot2).split(sep21).join("/");
|
|
120965
121311
|
const expectedSourcePath = sourceRelativePath === "." ? "./" : `./${sourceRelativePath}`;
|
|
120966
|
-
if (typeof sourcePath !== "string" ||
|
|
121312
|
+
if (typeof sourcePath !== "string" || isAbsolute44(sourcePath) || sourcePath !== expectedSourcePath || resolve42(dirname46(dirname46(candidate2.catalogPath)), sourcePath) !== pluginRoot2)
|
|
120967
121313
|
refuse8("marketplace source does not resolve to the frozen plugin closure; external source mapping is not supported by this schema");
|
|
120968
121314
|
const entry = captureClaudeMarketplaceEntry(candidate2.catalogPath, candidate2.marketplace, selected.plugin);
|
|
120969
121315
|
if (entry.sha256.length !== 64)
|
|
@@ -121024,7 +121370,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121024
121370
|
refuse8("Skills discovery preimage differs from its reviewed binding");
|
|
121025
121371
|
assertProjectDiscovery("claude", [request2.scope.projectPath], request2.native.home, canonical9, binding);
|
|
121026
121372
|
const stored = snapshot2.value.bridge?.discovery?.claude;
|
|
121027
|
-
if (!stored || !
|
|
121373
|
+
if (!stored || !isDeepStrictEqual21(stored, binding) || snapshot2.value.bridge?.home !== request2.native.home)
|
|
121028
121374
|
refuse8("Skills policy does not bind the reviewed current Claude discovery");
|
|
121029
121375
|
assertExemptUnchanged();
|
|
121030
121376
|
const delta = request2.delta;
|
|
@@ -121182,7 +121528,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121182
121528
|
refuse8("current known marketplace autoUpdate is not a boolean");
|
|
121183
121529
|
}
|
|
121184
121530
|
}
|
|
121185
|
-
if (!
|
|
121531
|
+
if (!isDeepStrictEqual21(delta.settingsAfter, settingsAfter))
|
|
121186
121532
|
refuse8("complete settings document differs from the exact selected plugin/options/environment/marketplace operations");
|
|
121187
121533
|
const marketplaceRowBefore = marketplaces?.[candidate2.marketplace];
|
|
121188
121534
|
if (marketplaceRowBefore !== undefined && !object11(marketplaceRowBefore))
|
|
@@ -121194,7 +121540,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121194
121540
|
if (marketplaceRowBefore?.lastUpdated !== undefined && !validUtcTimestamp(marketplaceRowBefore.lastUpdated))
|
|
121195
121541
|
refuse8("current marketplace update timestamp is invalid");
|
|
121196
121542
|
const targetMarketplaceLocation = candidate2.root;
|
|
121197
|
-
const sameMarketplaceSource =
|
|
121543
|
+
const sameMarketplaceSource = isDeepStrictEqual21(marketplaceRowBefore?.source, { source: "directory", path: candidate2.root }) && marketplaceRowBefore?.installLocation === targetMarketplaceLocation;
|
|
121198
121544
|
const afterMarketplace = {
|
|
121199
121545
|
source: { source: "directory", path: candidate2.root },
|
|
121200
121546
|
installLocation: targetMarketplaceLocation,
|
|
@@ -121203,7 +121549,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121203
121549
|
};
|
|
121204
121550
|
const marketplacesAfter = marketplaces ? structuredClone(marketplaces) : {};
|
|
121205
121551
|
marketplacesAfter[candidate2.marketplace] = afterMarketplace;
|
|
121206
|
-
if (!
|
|
121552
|
+
if (!isDeepStrictEqual21(delta.knownMarketplacesAfter, marketplacesAfter))
|
|
121207
121553
|
refuse8("complete marketplace document differs from the exact selected-directory marketplace operation");
|
|
121208
121554
|
const installedAfter = registrations ? structuredClone(registrations) : { version: 2, plugins: {} };
|
|
121209
121555
|
if (installedAfter.plugins === undefined)
|
|
@@ -121223,7 +121569,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121223
121569
|
nextRows[index] = targetRegistration;
|
|
121224
121570
|
installedAfter.plugins[pluginId2] = nextRows;
|
|
121225
121571
|
}
|
|
121226
|
-
if (!
|
|
121572
|
+
if (!isDeepStrictEqual21(delta.installedPluginsAfter, installedAfter))
|
|
121227
121573
|
refuse8("complete installed plugin document changes an unrelated registration or has target rows not derived from every selected candidate");
|
|
121228
121574
|
assertExemptUnchanged();
|
|
121229
121575
|
const semanticDocumentsSha256 = sha8(canonicalJson3({ settings: settingsAfter, knownMarketplaces: marketplacesAfter, installedPlugins: installedAfter }));
|
|
@@ -121302,7 +121648,7 @@ var init_claude_prospective_review = __esm(() => {
|
|
|
121302
121648
|
|
|
121303
121649
|
// src/lib/self-spawn.ts
|
|
121304
121650
|
import { realpathSync as realpathSync23 } from "fs";
|
|
121305
|
-
import { dirname as dirname47, isAbsolute as
|
|
121651
|
+
import { dirname as dirname47, isAbsolute as isAbsolute45, sep as sep22 } from "path";
|
|
121306
121652
|
function selfSpawnRoot(entry) {
|
|
121307
121653
|
const index = entry.indexOf(INSTALLED_PACKAGE);
|
|
121308
121654
|
const root2 = index > 0 ? entry.slice(0, index) : dirname47(entry);
|
|
@@ -121315,7 +121661,7 @@ function selfSpawnRoot(entry) {
|
|
|
121315
121661
|
function selfSpawnCommand(args2, options = {}) {
|
|
121316
121662
|
const runtime = options.runtime ?? process.execPath;
|
|
121317
121663
|
const entry = options.entry ?? process.argv[1];
|
|
121318
|
-
if (!runtime || !
|
|
121664
|
+
if (!runtime || !isAbsolute45(runtime) || !entry || !isAbsolute45(entry))
|
|
121319
121665
|
throw new Error("SKILLS_SELF_SPAWN_ENTRY_UNRESOLVED");
|
|
121320
121666
|
const root2 = selfSpawnRoot(entry);
|
|
121321
121667
|
const env3 = pinnedLauncherEnvironment(options.env ?? process.env);
|
|
@@ -121421,8 +121767,8 @@ var init_claude_installer_binding = __esm(() => {
|
|
|
121421
121767
|
});
|
|
121422
121768
|
|
|
121423
121769
|
// src/cli/commands/claude-installer-capture.ts
|
|
121424
|
-
import { closeSync as closeSync30, constants as constants29, fstatSync as fstatSync30, lstatSync as
|
|
121425
|
-
import { isAbsolute as
|
|
121770
|
+
import { closeSync as closeSync30, constants as constants29, fstatSync as fstatSync30, lstatSync as lstatSync47, openSync as openSync30, readSync as readSync22 } from "fs";
|
|
121771
|
+
import { isAbsolute as isAbsolute46, resolve as resolve43 } from "path";
|
|
121426
121772
|
function need11(condition, code2) {
|
|
121427
121773
|
if (!condition)
|
|
121428
121774
|
throw new CaptureRefusal(code2);
|
|
@@ -121436,11 +121782,11 @@ function exactKeys5(value, expected, operation) {
|
|
|
121436
121782
|
}
|
|
121437
121783
|
}
|
|
121438
121784
|
function canonicalPath2(value) {
|
|
121439
|
-
need11(typeof value === "string" &&
|
|
121785
|
+
need11(typeof value === "string" && isAbsolute46(value) && resolve43(value) === value && !/[\x00-\x1f\x7f]/.test(value), "INVALID_PATH: path fields must be normalized absolute paths without control characters");
|
|
121440
121786
|
}
|
|
121441
121787
|
function readRequest2(path) {
|
|
121442
121788
|
canonicalPath2(path);
|
|
121443
|
-
const before2 =
|
|
121789
|
+
const before2 = lstatSync47(path, { throwIfNoEntry: false });
|
|
121444
121790
|
if (!before2?.isFile() || before2.isSymbolicLink() || before2.size > MAX_REQUEST_BYTES)
|
|
121445
121791
|
throw new CaptureRefusal("INVALID_REQUEST_FILE: --request must name a regular non-symlink JSON file no larger than 64 KiB");
|
|
121446
121792
|
const fd = openSync30(path, constants29.O_RDONLY | (constants29.O_NOFOLLOW ?? 0) | constants29.O_NONBLOCK);
|
|
@@ -121455,7 +121801,7 @@ function readRequest2(path) {
|
|
|
121455
121801
|
break;
|
|
121456
121802
|
length += count;
|
|
121457
121803
|
}
|
|
121458
|
-
const after2 = fstatSync30(fd), current =
|
|
121804
|
+
const after2 = fstatSync30(fd), current = lstatSync47(path);
|
|
121459
121805
|
need11(length <= MAX_REQUEST_BYTES && length === opened.size && after2.size === opened.size && after2.mtimeMs === opened.mtimeMs && after2.ctimeMs === opened.ctimeMs && current.dev === opened.dev && current.ino === opened.ino && current.mtimeMs === opened.mtimeMs && current.ctimeMs === opened.ctimeMs, "INVALID_REQUEST_FILE: --request must remain unchanged while read");
|
|
121460
121806
|
try {
|
|
121461
121807
|
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
|
|
@@ -121607,10 +121953,10 @@ var exports_agent_integration = {};
|
|
|
121607
121953
|
__export(exports_agent_integration, {
|
|
121608
121954
|
registerAgentIntegration: () => registerAgentIntegration
|
|
121609
121955
|
});
|
|
121610
|
-
import { existsSync as existsSync36, lstatSync as
|
|
121956
|
+
import { existsSync as existsSync36, lstatSync as lstatSync48, readFileSync as readFileSync49, readSync as readSync23, writeFileSync as writeFileSync27 } from "fs";
|
|
121611
121957
|
import { createHash as createHash47 } from "crypto";
|
|
121612
121958
|
import { homedir as homedir14 } from "os";
|
|
121613
|
-
import { basename as basename24, isAbsolute as
|
|
121959
|
+
import { basename as basename24, isAbsolute as isAbsolute47, resolve as resolve44 } from "path";
|
|
121614
121960
|
function pinnedHookProfile(input3, configuredProfile) {
|
|
121615
121961
|
try {
|
|
121616
121962
|
const parsed = parseSkillContextInput(JSON.stringify(input3));
|
|
@@ -121745,7 +122091,7 @@ function registerAgentIntegration(parent) {
|
|
|
121745
122091
|
});
|
|
121746
122092
|
hook.command("native-catalog").requiredOption("--cwd <path>", "Absolute project directory observed by native Codex skills/list").requiredOption("--output <file>", "New private file for the projected native catalog").option("--codex-command <path>", "Installed Codex executable used by the native client", "codex").option("--json", "Output bounded capture metadata as JSON", false).description("Capture a reviewed Codex native skill catalog for exact hook enrollment").action(async (options) => {
|
|
121747
122093
|
try {
|
|
121748
|
-
if (!
|
|
122094
|
+
if (!isAbsolute47(options.cwd) || !isAbsolute47(options.output))
|
|
121749
122095
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_ABSOLUTE_PATH_REQUIRED");
|
|
121750
122096
|
if (existsSync36(options.output))
|
|
121751
122097
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
|
|
@@ -121769,7 +122115,7 @@ function registerAgentIntegration(parent) {
|
|
|
121769
122115
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
|
|
121770
122116
|
throw error61;
|
|
121771
122117
|
}
|
|
121772
|
-
const written =
|
|
122118
|
+
const written = lstatSync48(options.output);
|
|
121773
122119
|
if (!written.isFile() || written.isSymbolicLink() || (written.mode & 63) !== 0 || readFileSync49(options.output, "utf8") !== bytes)
|
|
121774
122120
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_READBACK_FAILED");
|
|
121775
122121
|
const receipt = {
|
|
@@ -121836,9 +122182,9 @@ function registerAgentIntegration(parent) {
|
|
|
121836
122182
|
});
|
|
121837
122183
|
hook.command("review-claude-candidate").requiredOption("--request <file>", "Frozen skills.claude-plugin-prospective-review/v1 JSON request").option("--json", "Return the validation-only receipt as JSON", false).description("Validate a prospective Claude plugin candidate and current preimages without changing native state; Harnesses must compare native and Skills paths against installed package-owned resolvers before trusting the receipt").action(async (options) => {
|
|
121838
122184
|
try {
|
|
121839
|
-
if (!
|
|
122185
|
+
if (!isAbsolute47(options.request))
|
|
121840
122186
|
throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: --request must be an absolute path");
|
|
121841
|
-
const stat3 =
|
|
122187
|
+
const stat3 = lstatSync48(options.request);
|
|
121842
122188
|
if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > 1024 * 1024)
|
|
121843
122189
|
throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: request must be a regular file no larger than 1 MiB");
|
|
121844
122190
|
const requestBytes = readFileSync49(options.request);
|
|
@@ -121974,12 +122320,12 @@ function registerAgentIntegration(parent) {
|
|
|
121974
122320
|
input3.hook_event_name = event;
|
|
121975
122321
|
const projects = [process.cwd()];
|
|
121976
122322
|
if (input3.cwd !== undefined) {
|
|
121977
|
-
if (typeof input3.cwd !== "string" || !
|
|
122323
|
+
if (typeof input3.cwd !== "string" || !isAbsolute47(input3.cwd) || input3.cwd.includes("\x00"))
|
|
121978
122324
|
throw new Error("Invalid native hook working directory");
|
|
121979
122325
|
projects.push(input3.cwd);
|
|
121980
122326
|
}
|
|
121981
122327
|
if (options.agent === "cursor") {
|
|
121982
|
-
if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !
|
|
122328
|
+
if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute47(path) || path.includes("\x00")))
|
|
121983
122329
|
throw new Error("Invalid Cursor workspace roots");
|
|
121984
122330
|
projects.push(...input3.workspace_roots);
|
|
121985
122331
|
input3.cwd ??= input3.workspace_roots[0] ?? process.cwd();
|
|
@@ -122770,7 +123116,7 @@ import {
|
|
|
122770
123116
|
mkdirSync as mkdirSync31,
|
|
122771
123117
|
readdirSync as readdirSync28,
|
|
122772
123118
|
readFileSync as readFileSync50,
|
|
122773
|
-
statSync as
|
|
123119
|
+
statSync as statSync26,
|
|
122774
123120
|
writeFileSync as writeFileSync30
|
|
122775
123121
|
} from "fs";
|
|
122776
123122
|
import { dirname as dirname48, join as join76, resolve as resolve45, sep as sep23 } from "path";
|
|
@@ -122867,7 +123213,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
122867
123213
|
});
|
|
122868
123214
|
continue;
|
|
122869
123215
|
}
|
|
122870
|
-
const info =
|
|
123216
|
+
const info = statSync26(entry.fullPath);
|
|
122871
123217
|
const manifestHash = manifestHashes.get(`${agent}${MANIFEST_HASH_KEY_SEP}${homeRelative}`) ?? null;
|
|
122872
123218
|
let verified = false;
|
|
122873
123219
|
if (manifestHash !== null) {
|
|
@@ -123124,10 +123470,10 @@ var init_hydrate = __esm(() => {
|
|
|
123124
123470
|
});
|
|
123125
123471
|
|
|
123126
123472
|
// src/lib/prepare-skill.ts
|
|
123127
|
-
import { createHash as createHash49, randomUUID as
|
|
123128
|
-
import { chmodSync as chmodSync5, existsSync as existsSync37, lstatSync as
|
|
123473
|
+
import { createHash as createHash49, randomUUID as randomUUID14 } from "crypto";
|
|
123474
|
+
import { chmodSync as chmodSync5, existsSync as existsSync37, lstatSync as lstatSync49, mkdirSync as mkdirSync32, mkdtempSync as mkdtempSync7, readFileSync as readFileSync51, readdirSync as readdirSync29, renameSync as renameSync16, rmSync as rmSync10, writeFileSync as writeFileSync31 } from "fs";
|
|
123129
123475
|
import { tmpdir as tmpdir2 } from "os";
|
|
123130
|
-
import { dirname as dirname49, isAbsolute as
|
|
123476
|
+
import { dirname as dirname49, isAbsolute as isAbsolute48, join as join77, relative as relative16, resolve as resolve46, sep as sep24 } from "path";
|
|
123131
123477
|
function prepareSkill(name, options) {
|
|
123132
123478
|
const normalized2 = normalizePortableSkillName(name);
|
|
123133
123479
|
if (!new RegExp(SEMVER_PATTERN).test(options.version))
|
|
@@ -123199,11 +123545,11 @@ ${validation.issues.map((issue2) => `${issue2.code}: ${issue2.message}`).join(`
|
|
|
123199
123545
|
if (snapshot2(path).identity !== before2.identity)
|
|
123200
123546
|
throw new Error("Skill changed during preparation; review the draft and run prepare again.");
|
|
123201
123547
|
if (changed3 && !options.dryRun) {
|
|
123202
|
-
const temporary = join77(path, `.skill-prepare-${
|
|
123548
|
+
const temporary = join77(path, `.skill-prepare-${randomUUID14()}.tmp`);
|
|
123203
123549
|
try {
|
|
123204
123550
|
writeFileSync31(temporary, candidateBytes, { flag: "wx", mode: manifestFile.mode });
|
|
123205
123551
|
chmodSync5(temporary, manifestFile.mode);
|
|
123206
|
-
|
|
123552
|
+
renameSync16(temporary, join77(path, "skill.json"));
|
|
123207
123553
|
} finally {
|
|
123208
123554
|
rmSync10(temporary, { force: true });
|
|
123209
123555
|
}
|
|
@@ -123234,7 +123580,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
|
|
|
123234
123580
|
if (typeof entry !== "string")
|
|
123235
123581
|
return;
|
|
123236
123582
|
const target = resolve46(root2, entry), rel = relative16(root2, target);
|
|
123237
|
-
if (
|
|
123583
|
+
if (isAbsolute48(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep24}`) || isAbsolute48(rel) || !existsSync37(target) || !lstatSync49(target).isFile()) {
|
|
123238
123584
|
throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
|
|
123239
123585
|
}
|
|
123240
123586
|
}
|
|
@@ -123319,7 +123665,7 @@ function compareVersions(left, right) {
|
|
|
123319
123665
|
return 0;
|
|
123320
123666
|
}
|
|
123321
123667
|
function snapshot2(root2) {
|
|
123322
|
-
const rootStat =
|
|
123668
|
+
const rootStat = lstatSync49(root2);
|
|
123323
123669
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
|
|
123324
123670
|
throw new Error("Skill root must be a real directory, not a symlink.");
|
|
123325
123671
|
const files = [], directories = [];
|
|
@@ -123332,7 +123678,7 @@ function snapshot2(root2) {
|
|
|
123332
123678
|
const path = relative17 ? `${relative17}/${name}` : name;
|
|
123333
123679
|
if (++count > 20000)
|
|
123334
123680
|
throw new Error("Skill exceeds the preparation entry limit (20000).");
|
|
123335
|
-
const absolute = join77(root2, path), stat3 =
|
|
123681
|
+
const absolute = join77(root2, path), stat3 = lstatSync49(absolute);
|
|
123336
123682
|
if (stat3.isSymbolicLink())
|
|
123337
123683
|
throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
|
|
123338
123684
|
if (stat3.isDirectory() && name === "node_modules")
|
|
@@ -123825,8 +124171,8 @@ var init_registry_sync = __esm(() => {
|
|
|
123825
124171
|
});
|
|
123826
124172
|
|
|
123827
124173
|
// src/lib/review-export.ts
|
|
123828
|
-
import { constants as constants32, closeSync as closeSync33, existsSync as existsSync38, fstatSync as fstatSync33, fsyncSync as fsyncSync10, lstatSync as
|
|
123829
|
-
import { basename as basename25, dirname as dirname51, isAbsolute as
|
|
124174
|
+
import { constants as constants32, closeSync as closeSync33, existsSync as existsSync38, fstatSync as fstatSync33, fsyncSync as fsyncSync10, lstatSync as lstatSync50, openSync as openSync33, realpathSync as realpathSync24, statSync as statSync27, writeFileSync as writeFileSync33 } from "fs";
|
|
124175
|
+
import { basename as basename25, dirname as dirname51, isAbsolute as isAbsolute49, join as join78, parse as parse13, resolve as resolve47, sep as sep25 } from "path";
|
|
123830
124176
|
function exactVersion(spec) {
|
|
123831
124177
|
const at2 = spec.indexOf("@");
|
|
123832
124178
|
const slug2 = spec.slice(0, at2);
|
|
@@ -123837,14 +124183,14 @@ function exactVersion(spec) {
|
|
|
123837
124183
|
return { slug: slug2, version: version2 };
|
|
123838
124184
|
}
|
|
123839
124185
|
function assertPrivateDestination(output2) {
|
|
123840
|
-
if (!
|
|
124186
|
+
if (!isAbsolute49(output2) || resolve47(output2) !== output2 || !basename25(output2).endsWith(".tar.gz")) {
|
|
123841
124187
|
throw new Error("Review output must be an absolute, normalized .tar.gz path.");
|
|
123842
124188
|
}
|
|
123843
124189
|
const parent = dirname51(output2);
|
|
123844
|
-
if (realpathSync24(parent) !== parent ||
|
|
124190
|
+
if (realpathSync24(parent) !== parent || lstatSync50(parent).isSymbolicLink()) {
|
|
123845
124191
|
throw new Error("Review output parent must be a real directory, not a symlink.");
|
|
123846
124192
|
}
|
|
123847
|
-
const parentStat =
|
|
124193
|
+
const parentStat = statSync27(parent);
|
|
123848
124194
|
if (!parentStat.isDirectory() || (parentStat.mode & 63) !== 0 || process.getuid && parentStat.uid !== process.getuid()) {
|
|
123849
124195
|
throw new Error("Review output parent must be an owner-only directory (mode 0700).");
|
|
123850
124196
|
}
|
|
@@ -124432,17 +124778,20 @@ __export(exports_private_publications, {
|
|
|
124432
124778
|
registerPrivatePublications: () => registerPrivatePublications
|
|
124433
124779
|
});
|
|
124434
124780
|
import { resolve as resolve48 } from "path";
|
|
124435
|
-
function
|
|
124781
|
+
function verifySessionOptions(options) {
|
|
124436
124782
|
if (options.userId === undefined !== (options.membershipId === undefined) || options.userId !== undefined && (!publicationUuid(options.userId) || !publicationUuid(options.membershipId)))
|
|
124437
124783
|
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide both observed --user-id and --membership-id UUIDs.");
|
|
124784
|
+
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
|
|
124785
|
+
throw new PrivatePublicationError("PUBLICATION_CODE_REQUIRED", "Use --code-stdin with a fresh code for noninteractive publishing.");
|
|
124786
|
+
}
|
|
124787
|
+
function verifyOptions(options, action) {
|
|
124788
|
+
verifySessionOptions(options);
|
|
124438
124789
|
if ((action === "publish" || action === "resume" || action === "cancel") && options.confirm !== true)
|
|
124439
124790
|
throw new PrivatePublicationError("PUBLICATION_CONFIRM_REQUIRED", "Use --confirm to approve this publication action.");
|
|
124440
124791
|
if (action === "publish" && (!publicationUuid(options.skillId) || Boolean(options.expectEmpty) === (options.expectedCurrentVersion !== undefined) || options.expectedCurrentVersion !== undefined && !publicationUuid(options.expectedCurrentVersion) || options.idempotencyKey !== undefined && !publicationUuid(options.idempotencyKey)))
|
|
124441
124792
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Provide --skill-id and exactly one of --expect-empty or --expected-current-version; optional --idempotency-key must be a UUID.");
|
|
124442
124793
|
if (options.waitSeconds !== undefined && (!/^(?:0|[1-9]\d{0,2})$/.test(options.waitSeconds) || Number(options.waitSeconds) > 300))
|
|
124443
124794
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Use --wait-seconds from 0 to 300.");
|
|
124444
|
-
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
|
|
124445
|
-
throw new PrivatePublicationError("PUBLICATION_CODE_REQUIRED", "Use --code-stdin with a fresh code for noninteractive publishing.");
|
|
124446
124795
|
}
|
|
124447
124796
|
function print2(result2, json3) {
|
|
124448
124797
|
if (json3)
|
|
@@ -124456,7 +124805,39 @@ function print2(result2, json3) {
|
|
|
124456
124805
|
process.exitCode = 2;
|
|
124457
124806
|
}
|
|
124458
124807
|
function registerPrivatePublications(parent) {
|
|
124459
|
-
const group = parent.command("publication").description("
|
|
124808
|
+
const group = parent.command("publication").description("Create private skills, publish and reconcile source versions on a compatible hosted server; execution is separate");
|
|
124809
|
+
group.command("create").allowExcessArguments(false).description("Create a private or team skill using fresh session verification (requires Pro)").argument("<slug>", "Lowercase kebab-case skill slug").requiredOption("--display-name <name>", "Skill display name").option("--description <text>", "Skill description", "").option("--visibility <visibility>", "private or team", "private").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--confirm", "Explicitly approve skill creation").option("--json", "Output validated skill identifiers without credentials or server free text").action(async (slug2, options) => {
|
|
124810
|
+
try {
|
|
124811
|
+
const body = checkedPrivateSkillCreate({ slug: slug2, displayName: options.displayName, description: options.description, visibility: options.visibility, confirm: options.confirm });
|
|
124812
|
+
verifySessionOptions(options);
|
|
124813
|
+
const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
|
|
124814
|
+
const pending = preparePrivatePublicationSession(context2);
|
|
124815
|
+
let code2;
|
|
124816
|
+
if (options.codeStdin)
|
|
124817
|
+
code2 = await readCode();
|
|
124818
|
+
else {
|
|
124819
|
+
await new RemoteSkillsAuthClient(pending.origin).requestCode(options.email);
|
|
124820
|
+
code2 = await promptCode();
|
|
124821
|
+
}
|
|
124822
|
+
if (code2 === null)
|
|
124823
|
+
return;
|
|
124824
|
+
const client2 = await pending.verify(options.email, code2);
|
|
124825
|
+
const result2 = await client2.createSkill({ ...body, confirm: true });
|
|
124826
|
+
if (options.json)
|
|
124827
|
+
console.log(JSON.stringify(result2));
|
|
124828
|
+
else {
|
|
124829
|
+
console.log(`Created ${result2.visibility} skill: ${result2.slug}`);
|
|
124830
|
+
console.log(`Skill ID: ${result2.id}`);
|
|
124831
|
+
}
|
|
124832
|
+
} catch (error61) {
|
|
124833
|
+
const result2 = error61 instanceof PrivatePublicationError ? privatePublicationCustomerError(error61) : { error: "Unable to verify the selected account and workspace for skill creation. Check the server, membership and fresh code; no credential was saved.", code: "SKILL_CREATE_SESSION_UNAVAILABLE", uncertain: false };
|
|
124834
|
+
if (options.json)
|
|
124835
|
+
console.log(JSON.stringify(result2));
|
|
124836
|
+
else
|
|
124837
|
+
console.error(result2.error);
|
|
124838
|
+
process.exitCode = 1;
|
|
124839
|
+
}
|
|
124840
|
+
});
|
|
124460
124841
|
const publishCommand = group.command("publish").allowExcessArguments(false).description("Publish private source with explicit current-version comparison").requiredOption("--recovery-dir <directory>", "New recovery directory for publish; existing directory for other actions").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--json", "Output a safe result without session credentials or upload URLs").option("--confirm", "Explicitly approve this action").argument("<directory>", "Validated local skill directory").requiredOption("--skill-id <uuid>", "Existing private/team skill UUID").option("--expected-current-version <uuid>", "Compare against the observed current version UUID").option("--expect-empty", "Require the skill to have no current version").option("--idempotency-key <uuid>", "Stable intent key; generated and saved before begin when omitted").option("--wait-seconds <seconds>", "Bounded status wait from 0 to 300", "60");
|
|
124461
124842
|
const statusCommand = group.command("status").allowExcessArguments(false).description("Inspect the exact saved publication").requiredOption("--recovery-dir <directory>", "New recovery directory for publish; existing directory for other actions").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--json", "Output a safe result without session credentials or upload URLs");
|
|
124462
124843
|
const resumeCommand = group.command("resume").allowExcessArguments(false).description("Reconcile the saved intent without creating a replacement").requiredOption("--recovery-dir <directory>", "New recovery directory for publish; existing directory for other actions").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--json", "Output a safe result without session credentials or upload URLs").option("--confirm", "Explicitly approve this action").option("--wait-seconds <seconds>", "Bounded status wait from 0 to 300", "60");
|
|
@@ -124466,17 +124847,18 @@ function registerPrivatePublications(parent) {
|
|
|
124466
124847
|
const options = action === "publish" ? args2[1] : args2[0];
|
|
124467
124848
|
try {
|
|
124468
124849
|
verifyOptions(options, action);
|
|
124850
|
+
const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
|
|
124851
|
+
const pending = preparePrivatePublicationSession(context2);
|
|
124469
124852
|
let code2;
|
|
124470
124853
|
if (options.codeStdin)
|
|
124471
124854
|
code2 = await readCode();
|
|
124472
124855
|
else {
|
|
124473
|
-
await new RemoteSkillsAuthClient(
|
|
124856
|
+
await new RemoteSkillsAuthClient(pending.origin).requestCode(options.email);
|
|
124474
124857
|
code2 = await promptCode();
|
|
124475
124858
|
}
|
|
124476
124859
|
if (code2 === null)
|
|
124477
124860
|
return;
|
|
124478
|
-
const
|
|
124479
|
-
const client2 = await privatePublicationSession(options.email, code2, context2), directory3 = resolve48(options.recoveryDir);
|
|
124861
|
+
const client2 = await pending.verify(options.email, code2), directory3 = resolve48(options.recoveryDir);
|
|
124480
124862
|
if (action === "publish")
|
|
124481
124863
|
await preparePrivatePublication(client2, resolve48(args2[0]), directory3, { skillId: options.skillId, expectedCurrentVersionId: options.expectedCurrentVersion ?? null, idempotencyKey: options.idempotencyKey });
|
|
124482
124864
|
const result2 = action === "publish" || action === "resume" ? await continuePrivatePublication(client2, directory3, { confirm: true, waitMs: Number(options.waitSeconds) * 1000 }) : await inspectPrivatePublication(client2, directory3, action === "cancel");
|
|
@@ -124494,7 +124876,6 @@ function registerPrivatePublications(parent) {
|
|
|
124494
124876
|
}
|
|
124495
124877
|
var init_private_publications = __esm(() => {
|
|
124496
124878
|
init_remote_auth();
|
|
124497
|
-
init_auth_store();
|
|
124498
124879
|
init_private_publication_customer();
|
|
124499
124880
|
init_private_publication_recovery();
|
|
124500
124881
|
init_remote_private_publications();
|
|
@@ -124513,6 +124894,14 @@ async function codeFor(client2, options) {
|
|
|
124513
124894
|
return promptCode();
|
|
124514
124895
|
}
|
|
124515
124896
|
function errorResult(error61, json3) {
|
|
124897
|
+
if (error61 instanceof SkillsFleetCredentialError) {
|
|
124898
|
+
if (json3)
|
|
124899
|
+
console.log(JSON.stringify({ error: error61.message, code: error61.code, next: error61.next }));
|
|
124900
|
+
else
|
|
124901
|
+
console.error(error61.message);
|
|
124902
|
+
process.exitCode = 1;
|
|
124903
|
+
return;
|
|
124904
|
+
}
|
|
124516
124905
|
const message = error61 instanceof NameInputError || error61 instanceof WorkspaceProfileError ? error61.message : "Unable to complete workspace sign-in. Check the selected server, profile, account and fresh verification code.";
|
|
124517
124906
|
if (json3)
|
|
124518
124907
|
console.log(JSON.stringify({ error: message }));
|
|
@@ -124566,6 +124955,7 @@ One workspace key saved. Use HASNA_PROFILE=${result2.profile} for subsequent com
|
|
|
124566
124955
|
}
|
|
124567
124956
|
var init_workspace_selection = __esm(() => {
|
|
124568
124957
|
init_auth_store();
|
|
124958
|
+
init_fleet_credentials();
|
|
124569
124959
|
init_remote_auth();
|
|
124570
124960
|
init_workspace_profile();
|
|
124571
124961
|
init_customer_verification();
|
|
@@ -124711,7 +125101,7 @@ function printWhoami(payload) {
|
|
|
124711
125101
|
}
|
|
124712
125102
|
function signInTarget(url2, json3) {
|
|
124713
125103
|
try {
|
|
124714
|
-
const target =
|
|
125104
|
+
const target = captureSkillsSignInTarget(process.env, {}, url2);
|
|
124715
125105
|
const refusal3 = gatewaySignInRefusal(target);
|
|
124716
125106
|
if (refusal3)
|
|
124717
125107
|
throw refusal3;
|
|
@@ -124722,7 +125112,10 @@ function signInTarget(url2, json3) {
|
|
|
124722
125112
|
}
|
|
124723
125113
|
}
|
|
124724
125114
|
function targetFlag(target) {
|
|
124725
|
-
return target.source === "--url" ? ` --url ${target.origin}` : "";
|
|
125115
|
+
return target.source === "--url" ? ` --url ${skillsShellArgument(target.origin)}` : "";
|
|
125116
|
+
}
|
|
125117
|
+
function skillsCommand(command, target) {
|
|
125118
|
+
return skillsProfileCommand(command, process.env, target.origin);
|
|
124726
125119
|
}
|
|
124727
125120
|
async function finishSignIn(result2, target, json3) {
|
|
124728
125121
|
const email5 = result2.user?.email;
|
|
@@ -124734,7 +125127,7 @@ async function finishSignIn(result2, target, json3) {
|
|
|
124734
125127
|
...organization2 ? { organization: organization2 } : {},
|
|
124735
125128
|
...result2.firstLogin !== undefined ? { firstLogin: result2.firstLogin } : {},
|
|
124736
125129
|
apiUrl: target.origin,
|
|
124737
|
-
next: ["
|
|
125130
|
+
next: [skillsCommand("setup agents", target)]
|
|
124738
125131
|
}));
|
|
124739
125132
|
return;
|
|
124740
125133
|
}
|
|
@@ -124744,24 +125137,24 @@ async function finishSignIn(result2, target, json3) {
|
|
|
124744
125137
|
console.log(source_default.dim(` Organization: ${result2.organization.name}`));
|
|
124745
125138
|
console.log(source_default.dim(` Server: ${target.origin}`));
|
|
124746
125139
|
console.log(source_default.dim(` API key saved to ${getAuthFilePath()}`));
|
|
124747
|
-
await offerAgentSetup();
|
|
125140
|
+
await offerAgentSetup(target);
|
|
124748
125141
|
}
|
|
124749
|
-
async function offerAgentSetup() {
|
|
125142
|
+
async function offerAgentSetup(target) {
|
|
124750
125143
|
const before2 = process.exitCode;
|
|
124751
125144
|
const answer = await prompt(`
|
|
124752
|
-
Register Skills with your coding agents now (
|
|
125145
|
+
Register Skills with your coding agents now (${skillsCommand("setup agents", target)})? [Y/n] `);
|
|
124753
125146
|
if (answer === null) {
|
|
124754
125147
|
process.exitCode = before2 ?? 0;
|
|
124755
125148
|
console.log(source_default.dim(`
|
|
124756
|
-
Skipped. Run it any time:
|
|
125149
|
+
Skipped. Run it any time: ${skillsCommand("setup agents", target)}`));
|
|
124757
125150
|
return;
|
|
124758
125151
|
}
|
|
124759
125152
|
if (answer !== "" && !/^y(es)?$/i.test(answer)) {
|
|
124760
|
-
console.log(source_default.dim(
|
|
125153
|
+
console.log(source_default.dim(`Skipped. Run it any time: ${skillsCommand("setup agents", target)}`));
|
|
124761
125154
|
return;
|
|
124762
125155
|
}
|
|
124763
125156
|
const { handleMcp: handleMcp2 } = await Promise.resolve().then(() => (init_runtime_mcp(), exports_runtime_mcp));
|
|
124764
|
-
await handleMcp2({ register: "all", json: false });
|
|
125157
|
+
await handleMcp2({ register: "all", json: false, apiUrl: target.origin });
|
|
124765
125158
|
process.exitCode = before2 ?? 0;
|
|
124766
125159
|
}
|
|
124767
125160
|
function promptHidden(question) {
|
|
@@ -124834,7 +125227,7 @@ async function doLogin(email5, code2, json3, target) {
|
|
|
124834
125227
|
if (!json3)
|
|
124835
125228
|
console.log(source_default.green("\u2713 Code sent to " + email5));
|
|
124836
125229
|
if (json3 || !isTTY || !process.stderr.isTTY) {
|
|
124837
|
-
console.log(JSON.stringify({ status: "code_sent", email: email5, message: `Supply the fresh six-digit code on stdin to:
|
|
125230
|
+
console.log(JSON.stringify({ status: "code_sent", email: email5, message: `Supply the fresh six-digit code on stdin to: ${skillsCommand("login", target)} --email ${skillsShellArgument(email5)} --code-stdin${targetFlag(target)}` }));
|
|
124838
125231
|
return;
|
|
124839
125232
|
}
|
|
124840
125233
|
const answer = await promptCode();
|
|
@@ -124844,6 +125237,7 @@ async function doLogin(email5, code2, json3, target) {
|
|
|
124844
125237
|
}
|
|
124845
125238
|
let verifyRes;
|
|
124846
125239
|
try {
|
|
125240
|
+
target.unchanged?.();
|
|
124847
125241
|
verifyRes = await apiRequest("/api/auth/verify", {
|
|
124848
125242
|
method: "POST",
|
|
124849
125243
|
body: JSON.stringify({ email: email5, code: code2 })
|
|
@@ -124857,7 +125251,7 @@ async function doLogin(email5, code2, json3, target) {
|
|
|
124857
125251
|
return;
|
|
124858
125252
|
}
|
|
124859
125253
|
try {
|
|
124860
|
-
await persistSignIn(verifyRes, origin, env3, "sign-in");
|
|
125254
|
+
await persistSignIn(verifyRes, origin, env3, "sign-in", target.unchanged);
|
|
124861
125255
|
} catch (err) {
|
|
124862
125256
|
writeCommandError(err, "Login succeeded but API key creation failed", json3);
|
|
124863
125257
|
return;
|
|
@@ -124886,6 +125280,7 @@ async function doApiKeyLogin(apiKey, json3, target) {
|
|
|
124886
125280
|
}
|
|
124887
125281
|
let whoami;
|
|
124888
125282
|
try {
|
|
125283
|
+
target.unchanged?.();
|
|
124889
125284
|
whoami = await apiRequest("/api/auth/whoami", {
|
|
124890
125285
|
headers: { Authorization: `Bearer ${trimmed}` }
|
|
124891
125286
|
}, origin);
|
|
@@ -124898,20 +125293,25 @@ async function doApiKeyLogin(apiKey, json3, target) {
|
|
|
124898
125293
|
const orgId = stringField2(identity6.orgId);
|
|
124899
125294
|
const orgSlug = stringField2(identity6.organization);
|
|
124900
125295
|
const userId = stringField2(identity6.userId);
|
|
124901
|
-
|
|
124902
|
-
|
|
124903
|
-
|
|
124904
|
-
|
|
124905
|
-
|
|
124906
|
-
|
|
124907
|
-
|
|
125296
|
+
try {
|
|
125297
|
+
saveAuthConfig({
|
|
125298
|
+
apiKey: trimmed,
|
|
125299
|
+
...email5 ? { email: email5 } : {},
|
|
125300
|
+
...orgId ? { orgId } : {},
|
|
125301
|
+
...orgSlug ? { orgSlug } : {},
|
|
125302
|
+
...userId ? { userId } : {}
|
|
125303
|
+
}, env3, origin, "api-key", target.unchanged);
|
|
125304
|
+
} catch (error61) {
|
|
125305
|
+
writeCommandError(error61, "API key verified but the selected profile changed", json3);
|
|
125306
|
+
return;
|
|
125307
|
+
}
|
|
124908
125308
|
if (json3 || !isTTY) {
|
|
124909
|
-
console.log(JSON.stringify({ ...identity6, status: "authenticated", apiUrl: origin, next: ["
|
|
125309
|
+
console.log(JSON.stringify({ ...identity6, status: "authenticated", apiUrl: origin, next: [skillsCommand("setup agents", target)] }, null, 2));
|
|
124910
125310
|
return;
|
|
124911
125311
|
}
|
|
124912
125312
|
printWhoami(identity6);
|
|
124913
125313
|
console.log(source_default.dim(`Server: ${origin}`));
|
|
124914
|
-
await offerAgentSetup();
|
|
125314
|
+
await offerAgentSetup(target);
|
|
124915
125315
|
}
|
|
124916
125316
|
function printDeviceCode(session, resumed, write) {
|
|
124917
125317
|
write(source_default.bold(resumed ? `
|
|
@@ -124932,12 +125332,12 @@ async function doDeviceLogin(options, target) {
|
|
|
124932
125332
|
const origin = target.origin;
|
|
124933
125333
|
const json3 = Boolean(options.json);
|
|
124934
125334
|
const interactive = Boolean(isTTY && !json3);
|
|
124935
|
-
const next =
|
|
125335
|
+
const next = `${skillsCommand("login", target)} --poll${targetFlag(target)}`;
|
|
124936
125336
|
let session = options.poll ? loadPendingDeviceSignIn(origin, env3) : null;
|
|
124937
125337
|
if (options.poll && !session) {
|
|
124938
125338
|
const others = pendingDeviceSignInOrigins(env3).filter((other) => other !== origin);
|
|
124939
125339
|
if (others.length > 0) {
|
|
124940
|
-
writeCommandError(new Error(`No pending sign-in for ${origin}. Pending: ${others.map((other) =>
|
|
125340
|
+
writeCommandError(new Error(`No pending sign-in for ${origin}. Pending: ${others.map((other) => `${skillsProfileCommand("login", process.env, other)} --poll --url ${skillsShellArgument(other)}`).join("; ")}`), "No pending sign-in", json3);
|
|
124941
125341
|
return;
|
|
124942
125342
|
}
|
|
124943
125343
|
}
|
|
@@ -124988,7 +125388,10 @@ Waiting for authentication...`));
|
|
|
124988
125388
|
try {
|
|
124989
125389
|
const deviceCode = session.deviceCode;
|
|
124990
125390
|
outcome = await pollDeviceAuthorization({
|
|
124991
|
-
poll: () =>
|
|
125391
|
+
poll: () => {
|
|
125392
|
+
target.unchanged?.();
|
|
125393
|
+
return pollDeviceToken(origin, deviceCode);
|
|
125394
|
+
},
|
|
124992
125395
|
intervalSeconds: session.interval,
|
|
124993
125396
|
deadline: Math.min(Date.now() + timeoutMs, session.expiresAt),
|
|
124994
125397
|
onSlowDown: (intervalMs) => {
|
|
@@ -125002,8 +125405,8 @@ Waiting for authentication...`));
|
|
|
125002
125405
|
}
|
|
125003
125406
|
if (outcome.status !== "authorized") {
|
|
125004
125407
|
const ended = {
|
|
125005
|
-
expired:
|
|
125006
|
-
invalid:
|
|
125408
|
+
expired: `The sign-in code expired before it was approved. Start again: ${skillsCommand("login", target)}${targetFlag(target)}`,
|
|
125409
|
+
invalid: `The server no longer recognises this sign-in code. Start again: ${skillsCommand("login", target)}${targetFlag(target)}`,
|
|
125007
125410
|
denied: "Sign-in was denied in the browser.",
|
|
125008
125411
|
timeout: `Device login timed out before browser authentication completed. Resume with: ${next}`,
|
|
125009
125412
|
cancelled: "Sign-in cancelled."
|
|
@@ -125019,7 +125422,7 @@ Waiting for authentication...`));
|
|
|
125019
125422
|
return;
|
|
125020
125423
|
}
|
|
125021
125424
|
try {
|
|
125022
|
-
await persistSignIn(outcome.result, origin, env3, "sign-in");
|
|
125425
|
+
await persistSignIn(outcome.result, origin, env3, "sign-in", target.unchanged);
|
|
125023
125426
|
} catch (err) {
|
|
125024
125427
|
writeCommandError(err, "Login succeeded but API key creation failed", json3);
|
|
125025
125428
|
return;
|
|
@@ -125271,6 +125674,7 @@ var init_auth = __esm(() => {
|
|
|
125271
125674
|
init_auth_store();
|
|
125272
125675
|
init_fleet_credentials();
|
|
125273
125676
|
init_remote_client();
|
|
125677
|
+
init_credential_profile_command();
|
|
125274
125678
|
init_sign_in();
|
|
125275
125679
|
init_remote_auth();
|
|
125276
125680
|
isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
@@ -125922,11 +126326,11 @@ var init_storage2 = __esm(() => {
|
|
|
125922
126326
|
});
|
|
125923
126327
|
|
|
125924
126328
|
// src/lib/registry-reconcile.ts
|
|
125925
|
-
import { existsSync as existsSync40, readFileSync as readFileSync53, statSync as
|
|
126329
|
+
import { existsSync as existsSync40, readFileSync as readFileSync53, statSync as statSync28, writeFileSync as writeFileSync34 } from "fs";
|
|
125926
126330
|
import { join as join80 } from "path";
|
|
125927
126331
|
function isDirectory2(path) {
|
|
125928
126332
|
try {
|
|
125929
|
-
return
|
|
126333
|
+
return statSync28(path).isDirectory();
|
|
125930
126334
|
} catch {
|
|
125931
126335
|
return false;
|
|
125932
126336
|
}
|
|
@@ -133962,6 +134366,7 @@ function InstallProgress({
|
|
|
133962
134366
|
// src/cli/components/AccountView.tsx
|
|
133963
134367
|
var import_react29 = __toESM(require_react(), 1);
|
|
133964
134368
|
init_fleet_credentials();
|
|
134369
|
+
init_credential_profile_command();
|
|
133965
134370
|
init_sign_in();
|
|
133966
134371
|
var jsx_dev_runtime6 = __toESM(require_jsx_dev_runtime(), 1);
|
|
133967
134372
|
var SLASH_COMMANDS = [
|
|
@@ -134021,7 +134426,7 @@ function AccountView({ action, argument, onDone }) {
|
|
|
134021
134426
|
});
|
|
134022
134427
|
return;
|
|
134023
134428
|
}
|
|
134024
|
-
const target =
|
|
134429
|
+
const target = captureSkillsSignInTarget(process.env, {}, argument);
|
|
134025
134430
|
const refusal3 = gatewaySignInRefusal(target);
|
|
134026
134431
|
if (refusal3)
|
|
134027
134432
|
throw refusal3;
|
|
@@ -134032,13 +134437,16 @@ function AccountView({ action, argument, onDone }) {
|
|
|
134032
134437
|
update2({ kind: "waiting", userCode: start.userCode, url: url2, origin: target.origin });
|
|
134033
134438
|
openVerificationPage(url2, target.origin);
|
|
134034
134439
|
const outcome = await pollDeviceAuthorization({
|
|
134035
|
-
poll: () =>
|
|
134440
|
+
poll: () => {
|
|
134441
|
+
target.unchanged?.();
|
|
134442
|
+
return pollDeviceToken(target.origin, start.deviceCode);
|
|
134443
|
+
},
|
|
134036
134444
|
intervalSeconds: start.interval,
|
|
134037
134445
|
deadline: Date.now() + start.expiresIn * 1000,
|
|
134038
134446
|
signal: controller.signal
|
|
134039
134447
|
});
|
|
134040
134448
|
if (outcome.status === "authorized") {
|
|
134041
|
-
await persistSignIn(outcome.result, target.origin);
|
|
134449
|
+
await persistSignIn(outcome.result, target.origin, process.env, "sign-in", target.unchanged);
|
|
134042
134450
|
const email4 = outcome.result.user?.email;
|
|
134043
134451
|
update2({
|
|
134044
134452
|
kind: "done",
|
|
@@ -134046,16 +134454,17 @@ function AccountView({ action, argument, onDone }) {
|
|
|
134046
134454
|
lines: [
|
|
134047
134455
|
{ text: email4 ? `Signed in as ${email4}` : "Signed in", tone: "good" },
|
|
134048
134456
|
{ text: `Server: ${target.origin}`, tone: "dim" },
|
|
134049
|
-
{ text:
|
|
134457
|
+
{ text: `Register Skills with your agents from a shell: ${skillsProfileCommand("setup agents", process.env, target.origin)}`, tone: "dim" }
|
|
134050
134458
|
]
|
|
134051
134459
|
});
|
|
134052
134460
|
return;
|
|
134053
134461
|
}
|
|
134462
|
+
const retry = argument !== undefined ? `/login ${target.origin}` : "/login";
|
|
134054
134463
|
const ended = {
|
|
134055
|
-
expired:
|
|
134056
|
-
invalid:
|
|
134464
|
+
expired: `The sign-in code expired before it was approved. Type ${retry} to start again.`,
|
|
134465
|
+
invalid: `The server no longer recognises this sign-in code. Type ${retry} to start again.`,
|
|
134057
134466
|
denied: "Sign-in was denied in the browser.",
|
|
134058
|
-
timeout:
|
|
134467
|
+
timeout: `Sign-in timed out. Type ${retry} to start again.`,
|
|
134059
134468
|
cancelled: "Sign-in cancelled."
|
|
134060
134469
|
}[outcome.status];
|
|
134061
134470
|
update2({ kind: "done", changed: false, lines: [{ text: ended, tone: "bad" }] });
|