@hasna/skills 0.10.24 → 0.10.26
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 +11 -0
- package/bin/index.js +248 -35
- package/bin/mcp.js +426 -312
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +245 -35
- package/dist/lib/agent-discovery-directories.d.ts +2 -2
- package/dist/lib/agent-discovery.d.ts +7 -0
- package/dist/lib/agent-integration.d.ts +1 -0
- package/dist/lib/codex-native-skill-catalog.d.ts +9 -1
- package/dist/lib/codex-plugin-skill-controls.d.ts +28 -1
- package/dist/sdk/index.js +245 -35
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -20019,7 +20019,7 @@ var package_default;
|
|
|
20019
20019
|
var init_package = __esm(() => {
|
|
20020
20020
|
package_default = {
|
|
20021
20021
|
name: "@hasna/skills",
|
|
20022
|
-
version: "0.10.
|
|
20022
|
+
version: "0.10.26",
|
|
20023
20023
|
description: "Skills library for AI coding agents",
|
|
20024
20024
|
type: "module",
|
|
20025
20025
|
bin: {
|
|
@@ -38266,6 +38266,18 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38266
38266
|
if (control.appSha256 !== undefined)
|
|
38267
38267
|
requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
|
|
38268
38268
|
}
|
|
38269
|
+
if (bridge.codexInactivePlugins !== undefined) {
|
|
38270
|
+
const controls = array3(bridge.codexInactivePlugins, 4096), ids = new Set;
|
|
38271
|
+
requireBound(controls.length === 0 || object4(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === "codex-cli 0.160.0" && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
|
|
38272
|
+
for (const control of controls) {
|
|
38273
|
+
requireBound(object4(control) && Object.keys(control).every((key) => ["pluginId", "namespace", "pluginParent", "sourceType", "sourceSha256"].includes(key)));
|
|
38274
|
+
text(control.pluginId, 1024);
|
|
38275
|
+
text(control.namespace, 64);
|
|
38276
|
+
text(control.pluginParent);
|
|
38277
|
+
requireBound(!ids.has(control.pluginId) && isAbsolute3(control.pluginParent) && resolve2(control.pluginParent) === control.pluginParent && ["local", "git", "npm"].includes(control.sourceType) && typeof control.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(control.sourceSha256));
|
|
38278
|
+
ids.add(control.pluginId);
|
|
38279
|
+
}
|
|
38280
|
+
}
|
|
38269
38281
|
if (bridge.disabledBuiltins !== undefined)
|
|
38270
38282
|
for (const builtin of array3(bridge.disabledBuiltins, AGENT_POLICY_LIMITS.builtinNames)) {
|
|
38271
38283
|
requireBound(object4(builtin));
|
|
@@ -38278,6 +38290,25 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38278
38290
|
text(agent, 128);
|
|
38279
38291
|
requireBound(object4(value));
|
|
38280
38292
|
text(value.agent, 128);
|
|
38293
|
+
if (value.codexInstallationInputs !== undefined) {
|
|
38294
|
+
const proof = record3(value.codexInstallationInputs, 4), inputs = array3(proof.plugins, 4096), ids = new Set;
|
|
38295
|
+
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && proof.version === "codex-cli 0.160.0" && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object4(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
|
|
38296
|
+
for (const input2 of inputs) {
|
|
38297
|
+
requireBound(object4(input2) && Object.keys(input2).every((key) => ["pluginId", "namespace", "pluginParent", "sourceRoot", "sourceSha256"].includes(key)));
|
|
38298
|
+
text(input2.pluginId, 1024);
|
|
38299
|
+
text(input2.namespace, 64);
|
|
38300
|
+
text(input2.pluginParent);
|
|
38301
|
+
text(input2.sourceRoot);
|
|
38302
|
+
requireBound(!ids.has(input2.pluginId) && [input2.pluginParent, input2.sourceRoot].every((path) => isAbsolute3(path) && resolve2(path) === path) && typeof input2.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(input2.sourceSha256));
|
|
38303
|
+
ids.add(input2.pluginId);
|
|
38304
|
+
}
|
|
38305
|
+
if (proof.directories !== undefined)
|
|
38306
|
+
for (const directory of array3(proof.directories, AGENT_POLICY_LIMITS.discoveryDirectories)) {
|
|
38307
|
+
requireBound(object4(directory));
|
|
38308
|
+
text(directory.path);
|
|
38309
|
+
requireBound(directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256));
|
|
38310
|
+
}
|
|
38311
|
+
}
|
|
38281
38312
|
for (const root of array3(value.roots, AGENT_POLICY_LIMITS.discoveryRoots))
|
|
38282
38313
|
text(root);
|
|
38283
38314
|
for (const source of array3(value.sources, AGENT_POLICY_LIMITS.discoverySources)) {
|
|
@@ -45378,7 +45409,7 @@ function safe(path) {
|
|
|
45378
45409
|
function same(before, after) {
|
|
45379
45410
|
return Boolean(after && after.isDirectory() && before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs);
|
|
45380
45411
|
}
|
|
45381
|
-
function capture(path, budget) {
|
|
45412
|
+
function capture(path, budget, excludedRoots) {
|
|
45382
45413
|
safe(path);
|
|
45383
45414
|
const root = lstatSync5(path, { throwIfNoEntry: false });
|
|
45384
45415
|
if (!root)
|
|
@@ -45407,7 +45438,7 @@ function capture(path, budget) {
|
|
|
45407
45438
|
budget.bytes += Buffer.byteLength(row);
|
|
45408
45439
|
need(budget.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
|
|
45409
45440
|
hash2.update(row);
|
|
45410
|
-
if (stat.isDirectory())
|
|
45441
|
+
if (stat.isDirectory() && !excludedRoots.includes(child))
|
|
45411
45442
|
walk(child, childRelative, stat, depth + 1);
|
|
45412
45443
|
}
|
|
45413
45444
|
need(same(before, lstatSync5(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
|
|
@@ -45416,16 +45447,18 @@ function capture(path, budget) {
|
|
|
45416
45447
|
safe(path);
|
|
45417
45448
|
return { path, sha256: hash2.digest("hex") };
|
|
45418
45449
|
}
|
|
45419
|
-
function captureDiscoveryDirectories(paths) {
|
|
45450
|
+
function captureDiscoveryDirectories(paths, excludedRoots = []) {
|
|
45420
45451
|
need(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
|
|
45421
45452
|
const budget = { entries: 0, bytes: 0 };
|
|
45422
|
-
|
|
45453
|
+
for (const root of excludedRoots)
|
|
45454
|
+
safe(root);
|
|
45455
|
+
return paths.map((path) => capture(path, budget, excludedRoots));
|
|
45423
45456
|
}
|
|
45424
|
-
function verifyDiscoveryDirectories(directories) {
|
|
45457
|
+
function verifyDiscoveryDirectories(directories, excludedRoots = []) {
|
|
45425
45458
|
need(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
|
|
45426
45459
|
for (const directory of directories)
|
|
45427
45460
|
need(directory && typeof directory === "object" && (directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256)), "Invalid native discovery directory digest");
|
|
45428
|
-
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path));
|
|
45461
|
+
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path), excludedRoots);
|
|
45429
45462
|
for (let i = 0;i < directories.length; i++)
|
|
45430
45463
|
need(current[i].sha256 === directories[i].sha256, `Native discovery directory membership changed; run skills hook install with a fresh discovery review: ${directories[i].path}`);
|
|
45431
45464
|
}
|
|
@@ -47413,6 +47446,17 @@ function hashClaudeSettingsReplacementV3(text2, budget) {
|
|
|
47413
47446
|
budget.remaining -= bytes;
|
|
47414
47447
|
return settingsDigest(text2, 3);
|
|
47415
47448
|
}
|
|
47449
|
+
function hashNativeJsonControls(text2, excludedMetadata) {
|
|
47450
|
+
need2(Buffer.byteLength(text2) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
|
|
47451
|
+
const value = parse8(text2);
|
|
47452
|
+
value.entries = value.entries.filter(([key, child]) => {
|
|
47453
|
+
if (key !== excludedMetadata)
|
|
47454
|
+
return true;
|
|
47455
|
+
need2(child.kind === "string" && child.value.length <= 128, "has invalid version metadata");
|
|
47456
|
+
return false;
|
|
47457
|
+
});
|
|
47458
|
+
return createHash8("sha256").update("hasna.skills.native-json-controls.v1\x00").update(JSON.stringify(canonical2(value))).digest("hex");
|
|
47459
|
+
}
|
|
47416
47460
|
var CLAUDE_SETTINGS_WITNESS_LIMITS, sameFile = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, BOOLEAN_PREFERENCES, ENUM_PREFERENCES, BUILTIN_MODEL_SELECTIONS, PERSISTED_EFFORT_LEVELS;
|
|
47417
47461
|
var init_claude_settings_witness = __esm(() => {
|
|
47418
47462
|
CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
@@ -47499,12 +47543,47 @@ var init_codex_hook_rpc = __esm(() => {
|
|
|
47499
47543
|
});
|
|
47500
47544
|
|
|
47501
47545
|
// src/lib/codex-native-skill-catalog.ts
|
|
47546
|
+
function codexPluginSourceIsConfigControlled(plugin) {
|
|
47547
|
+
const remoteRealms = ["openai-curated-remote", "created-by-me-remote", "workspace-directory", "workspace-shared-with-me", "workspace-shared-with-me-private", "workspace-shared-with-me-unlisted"];
|
|
47548
|
+
return Boolean(plugin.sourceType && ["local", "git", "npm"].includes(plugin.sourceType) && plugin.sourceSha256 && /^[a-f0-9]{64}$/.test(plugin.sourceSha256) && !plugin.remotePluginId && !remoteRealms.includes(plugin.id.slice(plugin.id.lastIndexOf("@") + 1)));
|
|
47549
|
+
}
|
|
47502
47550
|
var init_codex_native_skill_catalog = __esm(() => {
|
|
47503
47551
|
init_codex_hook_rpc();
|
|
47504
47552
|
init_codex_native_compatibility();
|
|
47553
|
+
init_claude_settings_witness();
|
|
47505
47554
|
});
|
|
47506
47555
|
|
|
47507
47556
|
// src/lib/codex-plugin-skill-controls.ts
|
|
47557
|
+
import { basename as basename5, dirname as dirname10, join as join16, relative as relative4, resolve as resolve9, sep as sep4 } from "path";
|
|
47558
|
+
import { lstatSync as lstatSync11, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as realpathSync3 } from "fs";
|
|
47559
|
+
function refuse() {
|
|
47560
|
+
throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
|
|
47561
|
+
}
|
|
47562
|
+
function sourceInputUnchanged(input2, cache, read) {
|
|
47563
|
+
try {
|
|
47564
|
+
const parts = relative4(cache, input2.pluginParent).split(sep4);
|
|
47565
|
+
if (parts.length !== 2 || parts.some((part) => !identifier2(part)) || parts[1] !== input2.namespace || input2.pluginId !== `${parts[1]}@${parts[0]}` || !codexPluginSourceIsConfigControlled({ id: input2.pluginId, sourceType: "local", sourceSha256: input2.sourceSha256 }) || input2.sourceSha256 !== hashNativeJsonControls(JSON.stringify({ type: "local", path: input2.sourceRoot })) || resolve9(input2.sourceRoot) !== input2.sourceRoot || !lstatSync11(input2.sourceRoot).isDirectory() || realpathSync3(input2.sourceRoot) !== input2.sourceRoot || input2.sourceRoot === cache || input2.sourceRoot.startsWith(cache + sep4) || cache.startsWith(input2.sourceRoot + sep4))
|
|
47566
|
+
return false;
|
|
47567
|
+
const path = join16(input2.sourceRoot, ".codex-plugin/plugin.json"), stat = lstatSync11(path);
|
|
47568
|
+
if (!stat.isFile() || stat.size > 1024 * 1024 || realpathSync3(path) !== path)
|
|
47569
|
+
return false;
|
|
47570
|
+
const text2 = read(path);
|
|
47571
|
+
hashNativeJsonControls(text2);
|
|
47572
|
+
const manifest = JSON.parse(text2);
|
|
47573
|
+
return Boolean(manifest && typeof manifest === "object" && !Array.isArray(manifest) && manifest.name === input2.namespace);
|
|
47574
|
+
} catch {
|
|
47575
|
+
return false;
|
|
47576
|
+
}
|
|
47577
|
+
}
|
|
47578
|
+
function reviewedCodexPluginSourceRoots(cache, inputs, read) {
|
|
47579
|
+
if (!Array.isArray(inputs) || inputs.length > 4096 || new Set(inputs.map((input2) => input2.pluginId)).size !== inputs.length || new Set(inputs.map((input2) => input2.sourceRoot)).size !== inputs.length || inputs.some((input2) => !sourceInputUnchanged(input2, cache, read)))
|
|
47580
|
+
refuse();
|
|
47581
|
+
const roots = inputs.map((input2) => input2.sourceRoot);
|
|
47582
|
+
if (roots.some((root) => roots.some((other) => root !== other && root.startsWith(other + sep4))))
|
|
47583
|
+
refuse();
|
|
47584
|
+
return roots;
|
|
47585
|
+
}
|
|
47586
|
+
var identifier2 = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(v);
|
|
47508
47587
|
var init_codex_plugin_skill_controls = __esm(() => {
|
|
47509
47588
|
init_claude_settings_witness();
|
|
47510
47589
|
init_codex_native_compatibility();
|
|
@@ -47759,8 +47838,8 @@ var init_codex_settings_witness = __esm(() => {
|
|
|
47759
47838
|
});
|
|
47760
47839
|
|
|
47761
47840
|
// src/lib/managed-policy.ts
|
|
47762
|
-
import { closeSync as closeSync9, constants as constants6, fstatSync as fstatSync9, lstatSync as
|
|
47763
|
-
import { join as
|
|
47841
|
+
import { closeSync as closeSync9, constants as constants6, fstatSync as fstatSync9, lstatSync as lstatSync12, openSync as openSync9, readSync as readSync5 } from "fs";
|
|
47842
|
+
import { join as join17 } from "path";
|
|
47764
47843
|
function refusal(reason = "is unreadable") {
|
|
47765
47844
|
return new SkillSelectionError("INVALID_AGENT_POLICY", `The Skills agent loading policy ${reason}; refusing legacy fallback.`);
|
|
47766
47845
|
}
|
|
@@ -47785,10 +47864,10 @@ function parseManagedSkillPolicy(text2) {
|
|
|
47785
47864
|
return value;
|
|
47786
47865
|
}
|
|
47787
47866
|
function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
|
|
47788
|
-
const path =
|
|
47867
|
+
const path = join17(dataDir2, "agent-policy.json");
|
|
47789
47868
|
let descriptor, observed = false;
|
|
47790
47869
|
try {
|
|
47791
|
-
const stat =
|
|
47870
|
+
const stat = lstatSync12(path);
|
|
47792
47871
|
observed = true;
|
|
47793
47872
|
if (!stat.isFile() || stat.isSymbolicLink())
|
|
47794
47873
|
throw refusal();
|
|
@@ -47814,7 +47893,7 @@ function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
|
|
|
47814
47893
|
return { text: text2, value: parseManagedSkillPolicy(text2) };
|
|
47815
47894
|
} catch (error61) {
|
|
47816
47895
|
if (error61.code === "ENOENT" && !observed) {
|
|
47817
|
-
if (
|
|
47896
|
+
if (lstatSync12(path, { throwIfNoEntry: false }) === undefined)
|
|
47818
47897
|
return null;
|
|
47819
47898
|
}
|
|
47820
47899
|
if (error61 instanceof SkillSelectionError)
|
|
@@ -47916,12 +47995,12 @@ var init_skill_aliases = __esm(() => {
|
|
|
47916
47995
|
|
|
47917
47996
|
// src/lib/project-state.ts
|
|
47918
47997
|
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
|
|
47919
|
-
import { join as
|
|
47998
|
+
import { join as join18 } from "path";
|
|
47920
47999
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
47921
|
-
return
|
|
48000
|
+
return join18(targetDir, SKILLS_PROJECT_DIR);
|
|
47922
48001
|
}
|
|
47923
48002
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
47924
|
-
return
|
|
48003
|
+
return join18(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
47925
48004
|
}
|
|
47926
48005
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
47927
48006
|
const path = getProjectConfigPath(targetDir);
|
|
@@ -48037,7 +48116,7 @@ var init_project_state = __esm(() => {
|
|
|
48037
48116
|
|
|
48038
48117
|
// src/lib/installer.ts
|
|
48039
48118
|
import { existsSync as existsSync9, readFileSync as readFileSync13, rmSync } from "fs";
|
|
48040
|
-
import { join as
|
|
48119
|
+
import { join as join19 } from "path";
|
|
48041
48120
|
import { homedir as homedir2 } from "os";
|
|
48042
48121
|
function getSkillPath(name) {
|
|
48043
48122
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
@@ -48047,7 +48126,7 @@ function getSkillPath(name) {
|
|
|
48047
48126
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
48048
48127
|
if (extensionPath)
|
|
48049
48128
|
return extensionPath;
|
|
48050
|
-
return
|
|
48129
|
+
return join19(getPortableSkillsRoot(), skillName);
|
|
48051
48130
|
}
|
|
48052
48131
|
function getCanonicalSkillName(name) {
|
|
48053
48132
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
@@ -48101,11 +48180,11 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
48101
48180
|
const base = projectDir || process.cwd();
|
|
48102
48181
|
switch (agent) {
|
|
48103
48182
|
case "pi":
|
|
48104
|
-
return scope === "project" ?
|
|
48183
|
+
return scope === "project" ? join19(base, ".pi", "skills") : join19(homedir2(), ".pi", "agent", "skills");
|
|
48105
48184
|
case "opencode":
|
|
48106
|
-
return scope === "project" ?
|
|
48185
|
+
return scope === "project" ? join19(base, ".opencode", "skills") : join19(homedir2(), ".config", "opencode", "skills");
|
|
48107
48186
|
default:
|
|
48108
|
-
return scope === "project" ?
|
|
48187
|
+
return scope === "project" ? join19(base, `.${agent}`, "skills") : join19(homedir2(), `.${agent}`, "skills");
|
|
48109
48188
|
}
|
|
48110
48189
|
}
|
|
48111
48190
|
function warnMissingDependencies(name, targetDir) {
|
|
@@ -48120,7 +48199,7 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
48120
48199
|
}
|
|
48121
48200
|
}
|
|
48122
48201
|
function readBundledSkillVersion(name) {
|
|
48123
|
-
const pkgPath =
|
|
48202
|
+
const pkgPath = join19(getSkillPath(name), "package.json");
|
|
48124
48203
|
if (!existsSync9(pkgPath))
|
|
48125
48204
|
return "unknown";
|
|
48126
48205
|
try {
|
|
@@ -48189,11 +48268,11 @@ var init_skill_doc_file = __esm(() => {
|
|
|
48189
48268
|
|
|
48190
48269
|
// src/lib/skillinfo.ts
|
|
48191
48270
|
import { existsSync as existsSync10, readFileSync as readFileSync14 } from "fs";
|
|
48192
|
-
import { join as
|
|
48271
|
+
import { join as join20 } from "path";
|
|
48193
48272
|
function isInstructionSkillDir(skillPath, meta3) {
|
|
48194
48273
|
if (meta3?.kind === "instruction")
|
|
48195
48274
|
return true;
|
|
48196
|
-
const skillMdPath =
|
|
48275
|
+
const skillMdPath = join20(skillPath, "SKILL.md");
|
|
48197
48276
|
if (!existsSync10(skillMdPath))
|
|
48198
48277
|
return false;
|
|
48199
48278
|
try {
|
|
@@ -48207,9 +48286,9 @@ function getSkillDocs(name) {
|
|
|
48207
48286
|
if (!existsSync10(skillPath))
|
|
48208
48287
|
return null;
|
|
48209
48288
|
return {
|
|
48210
|
-
skillMd: readIfExists(
|
|
48211
|
-
readme: readIfExists(
|
|
48212
|
-
claudeMd: readIfExists(
|
|
48289
|
+
skillMd: readIfExists(join20(skillPath, "SKILL.md")),
|
|
48290
|
+
readme: readIfExists(join20(skillPath, "README.md")),
|
|
48291
|
+
claudeMd: readIfExists(join20(skillPath, "CLAUDE.md"))
|
|
48213
48292
|
};
|
|
48214
48293
|
}
|
|
48215
48294
|
function getSkillBestDoc(name, file2) {
|
|
@@ -48225,14 +48304,14 @@ function getSkillRequirements(name) {
|
|
|
48225
48304
|
return null;
|
|
48226
48305
|
const texts = [];
|
|
48227
48306
|
for (const file2 of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
48228
|
-
const content = readIfExists(
|
|
48307
|
+
const content = readIfExists(join20(skillPath, file2));
|
|
48229
48308
|
if (content)
|
|
48230
48309
|
texts.push(content);
|
|
48231
48310
|
}
|
|
48232
48311
|
const meta3 = getSkill(name);
|
|
48233
48312
|
let dependencies = {};
|
|
48234
48313
|
try {
|
|
48235
|
-
dependencies = JSON.parse(readFileSync14(
|
|
48314
|
+
dependencies = JSON.parse(readFileSync14(join20(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
48236
48315
|
} catch {}
|
|
48237
48316
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta3);
|
|
48238
48317
|
}
|
|
@@ -48294,7 +48373,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
48294
48373
|
error: `Skill '${name}' is an instruction skill (kind: instruction) and is not runnable. Instruction skills are consumed by coding agents via SKILL.md, not executed with 'skills run'.`
|
|
48295
48374
|
};
|
|
48296
48375
|
}
|
|
48297
|
-
const pkgPath =
|
|
48376
|
+
const pkgPath = join20(skillPath, "package.json");
|
|
48298
48377
|
if (!existsSync10(pkgPath)) {
|
|
48299
48378
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
48300
48379
|
}
|
|
@@ -48314,12 +48393,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
48314
48393
|
} catch {
|
|
48315
48394
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
48316
48395
|
}
|
|
48317
|
-
const entryPath =
|
|
48396
|
+
const entryPath = join20(skillPath, entryPoint2);
|
|
48318
48397
|
if (!existsSync10(entryPath)) {
|
|
48319
48398
|
return { exitCode: 1, error: `Entry point '${entryPoint2}' not found in skill '${name}'` };
|
|
48320
48399
|
}
|
|
48321
48400
|
const env = { ...process.env, ...options.env };
|
|
48322
|
-
if (!existsSync10(
|
|
48401
|
+
if (!existsSync10(join20(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
|
|
48323
48402
|
const failure = await prepareSkillDependencies(skillPath, env, options.preparationTimeoutMs);
|
|
48324
48403
|
if (failure)
|
|
48325
48404
|
return failure;
|
|
@@ -48345,7 +48424,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
48345
48424
|
function detectProjectSkills(cwd = process.cwd()) {
|
|
48346
48425
|
let pkg;
|
|
48347
48426
|
try {
|
|
48348
|
-
pkg = JSON.parse(readFileSync14(
|
|
48427
|
+
pkg = JSON.parse(readFileSync14(join20(cwd, "package.json"), "utf8"));
|
|
48349
48428
|
} catch {
|
|
48350
48429
|
return { detected: [], recommended: [] };
|
|
48351
48430
|
}
|
|
@@ -48633,11 +48712,11 @@ var init_plugin_projection = __esm(() => {
|
|
|
48633
48712
|
});
|
|
48634
48713
|
|
|
48635
48714
|
// src/lib/plugin-projection-store.ts
|
|
48636
|
-
import { constants as constants7, closeSync as closeSync10, fchmodSync, fstatSync as fstatSync10, fsyncSync as fsyncSync2, linkSync, lstatSync as
|
|
48637
|
-
import { dirname as
|
|
48715
|
+
import { constants as constants7, closeSync as closeSync10, fchmodSync, fstatSync as fstatSync10, fsyncSync as fsyncSync2, linkSync, lstatSync as lstatSync13, mkdirSync as mkdirSync6, openSync as openSync10, opendirSync as opendirSync2, readSync as readSync6, renameSync as renameSync2, rmdirSync as rmdirSync2, rmSync as rmSync2, unlinkSync as unlinkSync3, writeSync as writeSync2 } from "fs";
|
|
48716
|
+
import { dirname as dirname11, isAbsolute as isAbsolute9, join as join21, parse as parse9, resolve as resolve10 } from "path";
|
|
48638
48717
|
function stat(path) {
|
|
48639
48718
|
try {
|
|
48640
|
-
return
|
|
48719
|
+
return lstatSync13(path, { bigint: true });
|
|
48641
48720
|
} catch (error61) {
|
|
48642
48721
|
if (missing(error61))
|
|
48643
48722
|
return null;
|
|
@@ -48645,7 +48724,7 @@ function stat(path) {
|
|
|
48645
48724
|
}
|
|
48646
48725
|
}
|
|
48647
48726
|
function canonical5(path) {
|
|
48648
|
-
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute9(path) &&
|
|
48727
|
+
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute9(path) && resolve10(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
48649
48728
|
}
|
|
48650
48729
|
function owner(stats, system = false) {
|
|
48651
48730
|
const current = uid();
|
|
@@ -48656,11 +48735,11 @@ function same3(left, right, identityOnly = false) {
|
|
|
48656
48735
|
}
|
|
48657
48736
|
function ancestors(path, create = false) {
|
|
48658
48737
|
canonical5(path);
|
|
48659
|
-
const result = [], parent =
|
|
48738
|
+
const result = [], parent = dirname11(path), filesystemRoot = parse9(parent).root;
|
|
48660
48739
|
let current = filesystemRoot;
|
|
48661
48740
|
for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
|
|
48662
48741
|
if (segment)
|
|
48663
|
-
current =
|
|
48742
|
+
current = join21(current, segment);
|
|
48664
48743
|
let currentStat = stat(current);
|
|
48665
48744
|
if (!currentStat && create) {
|
|
48666
48745
|
try {
|
|
@@ -48758,7 +48837,7 @@ function directoryNames(path) {
|
|
|
48758
48837
|
function snapshotPluginTree(root, options = {}) {
|
|
48759
48838
|
const chain = ancestors(root), entries = [], files = [], directories = [];
|
|
48760
48839
|
let bytes = 0, visited = 0;
|
|
48761
|
-
const visit3 = (directory,
|
|
48840
|
+
const visit3 = (directory, relative5) => {
|
|
48762
48841
|
const before = stat(directory);
|
|
48763
48842
|
pluginNeed(before && before.isDirectory() && !before.isSymbolicLink(), "Plugin tree must contain real directories");
|
|
48764
48843
|
const names = directoryNames(directory);
|
|
@@ -48766,18 +48845,18 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
48766
48845
|
directories.push({ path: directory, stat: before, names });
|
|
48767
48846
|
for (const name of names) {
|
|
48768
48847
|
pluginNeed(++visited <= PLUGIN_PROJECTION_LIMITS.files * 50, "Plugin tree membership exceeds its limit");
|
|
48769
|
-
const path =
|
|
48848
|
+
const path = relative5 ? `${relative5}/${name}` : name;
|
|
48770
48849
|
pluginNeed(new TextEncoder().encode(path).byteLength <= 100 && !/[\\:\x00-\x1f\x7f]/u.test(path), "Plugin entry path exceeds its limit or is unsafe");
|
|
48771
|
-
const absolute =
|
|
48850
|
+
const absolute = join21(directory, name), entryStat = stat(absolute);
|
|
48772
48851
|
pluginNeed(entryStat, "Plugin tree member disappeared");
|
|
48773
|
-
if (
|
|
48852
|
+
if (relative5 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
|
|
48774
48853
|
const bytes2 = readBytes(absolute, 32, "native-pin");
|
|
48775
48854
|
pluginNeed(/^[1-9][0-9]{12}$/.test(new TextDecoder().decode(bytes2)), "Malformed native orphan timestamp");
|
|
48776
48855
|
same3(entryStat, stat(absolute));
|
|
48777
48856
|
files.push({ path: absolute, stat: entryStat });
|
|
48778
48857
|
continue;
|
|
48779
48858
|
}
|
|
48780
|
-
if (
|
|
48859
|
+
if (relative5 === "" && name === ".in_use" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
|
|
48781
48860
|
pluginNeed(entryStat.isDirectory() && !entryStat.isSymbolicLink(), "Native plugin pins require a real directory");
|
|
48782
48861
|
owner(entryStat);
|
|
48783
48862
|
const pins = directoryNames(absolute);
|
|
@@ -48785,7 +48864,7 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
48785
48864
|
directories.push({ path: absolute, stat: entryStat, names: pins });
|
|
48786
48865
|
for (const pin of pins) {
|
|
48787
48866
|
pluginNeed(/^[1-9][0-9]{0,9}$/.test(pin) && Number(pin) <= 2147483647, "Unrecognized native plugin pin name");
|
|
48788
|
-
const pinPath =
|
|
48867
|
+
const pinPath = join21(absolute, pin), pinStat = stat(pinPath);
|
|
48789
48868
|
pluginNeed(pinStat, "Native plugin pin disappeared");
|
|
48790
48869
|
const bytes2 = readBytes(pinPath, 4096, "native-pin");
|
|
48791
48870
|
let value;
|
|
@@ -48882,7 +48961,7 @@ var init_selected_manifest = __esm(() => {
|
|
|
48882
48961
|
});
|
|
48883
48962
|
|
|
48884
48963
|
// src/lib/plugin-admission.ts
|
|
48885
|
-
import { isAbsolute as isAbsolute10, join as
|
|
48964
|
+
import { isAbsolute as isAbsolute10, join as join22, resolve as resolve11 } from "path";
|
|
48886
48965
|
function validatePluginTarget(value) {
|
|
48887
48966
|
pluginKeys(value, ["schemaVersion", "pluginId", "registrations", "native", "resolver"]);
|
|
48888
48967
|
pluginNeed(value.schemaVersion === 1, "Invalid plugin admission target");
|
|
@@ -48892,7 +48971,7 @@ function validatePluginTarget(value) {
|
|
|
48892
48971
|
for (const registration of value.registrations) {
|
|
48893
48972
|
pluginKeys(registration, ["scope", "projectPath"]);
|
|
48894
48973
|
pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
|
|
48895
|
-
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute10(registration.projectPath) &&
|
|
48974
|
+
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute10(registration.projectPath) && resolve11(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
|
|
48896
48975
|
const key = JSON.stringify([registration.scope, registration.projectPath]);
|
|
48897
48976
|
pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
|
|
48898
48977
|
scopes.add(key);
|
|
@@ -48900,7 +48979,7 @@ function validatePluginTarget(value) {
|
|
|
48900
48979
|
for (const key of ["native", "resolver"]) {
|
|
48901
48980
|
pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
|
|
48902
48981
|
pluginText(value[key].executable);
|
|
48903
|
-
pluginNeed(isAbsolute10(value[key].executable) &&
|
|
48982
|
+
pluginNeed(isAbsolute10(value[key].executable) && resolve11(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
|
|
48904
48983
|
pluginDigest(value[key].digest);
|
|
48905
48984
|
}
|
|
48906
48985
|
pluginNeed(["2.1.274", "2.1.276"].includes(value.native.version), "Plugin admission requires a certified Claude command-source runtime (2.1.274 or 2.1.276)");
|
|
@@ -49043,12 +49122,12 @@ function pluginResolverCommand(binding) {
|
|
|
49043
49122
|
}
|
|
49044
49123
|
function pluginBindingPath(storeRoot, id) {
|
|
49045
49124
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
49046
|
-
return
|
|
49125
|
+
return join22(storeRoot, "bindings", `${id}.json`);
|
|
49047
49126
|
}
|
|
49048
49127
|
function pluginReceiptPath(storeRoot, id, digest) {
|
|
49049
49128
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
49050
49129
|
pluginDigest(digest);
|
|
49051
|
-
return
|
|
49130
|
+
return join22(storeRoot, "receipts", id, `${digest.slice(7)}.json`);
|
|
49052
49131
|
}
|
|
49053
49132
|
function readPluginBinding(storeRoot, id) {
|
|
49054
49133
|
const value = readPluginJson(pluginBindingPath(storeRoot, id));
|
|
@@ -49068,7 +49147,7 @@ function readPluginAdmissionReceipt(storeRoot, id, digest) {
|
|
|
49068
49147
|
pluginNeed(receipt.plan.bindingId === id && receipt.plan.planDigest === digest, "Plugin receipt identity differs from its filename");
|
|
49069
49148
|
const binding = readPluginBinding(storeRoot, id);
|
|
49070
49149
|
pluginNeed(canonicalJson(binding) === canonicalJson(receipt.plan.binding) && receipt.plan.sourceCommand === pluginResolverCommand(binding), "Plugin receipt binding changed");
|
|
49071
|
-
pluginNeed(receipt.materializedPath ===
|
|
49150
|
+
pluginNeed(receipt.materializedPath === join22(storeRoot, "objects", id, digest.slice(7)), "Plugin receipt points outside its immutable materialization");
|
|
49072
49151
|
pluginText(receipt.admittedAt, 64);
|
|
49073
49152
|
pluginNeed(Number.isFinite(Date.parse(receipt.admittedAt)), "Invalid plugin admission time");
|
|
49074
49153
|
return receipt;
|
|
@@ -49085,8 +49164,8 @@ var init_plugin_admission = __esm(() => {
|
|
|
49085
49164
|
});
|
|
49086
49165
|
|
|
49087
49166
|
// src/lib/plugin-discovery.ts
|
|
49088
|
-
import { closeSync as closeSync11, constants as constants8, fstatSync as fstatSync11, lstatSync as
|
|
49089
|
-
import { basename as
|
|
49167
|
+
import { closeSync as closeSync11, constants as constants8, fstatSync as fstatSync11, lstatSync as lstatSync14, openSync as openSync11, opendirSync as opendirSync3, readSync as readSync7 } from "fs";
|
|
49168
|
+
import { basename as basename6, dirname as dirname12, isAbsolute as isAbsolute11, join as join23, resolve as resolve12 } from "path";
|
|
49090
49169
|
function validateManagedPluginWitnesses(value) {
|
|
49091
49170
|
pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
|
|
49092
49171
|
const seen = new Set;
|
|
@@ -49095,21 +49174,21 @@ function validateManagedPluginWitnesses(value) {
|
|
|
49095
49174
|
pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
|
|
49096
49175
|
seen.add(item.bindingId);
|
|
49097
49176
|
pluginText(item.storeRoot);
|
|
49098
|
-
pluginNeed(isAbsolute11(item.storeRoot) &&
|
|
49177
|
+
pluginNeed(isAbsolute11(item.storeRoot) && resolve12(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
|
|
49099
49178
|
}
|
|
49100
49179
|
}
|
|
49101
49180
|
function safe3(path) {
|
|
49102
49181
|
pluginText(path);
|
|
49103
|
-
pluginNeed(isAbsolute11(path) &&
|
|
49104
|
-
for (let at = path;; at =
|
|
49105
|
-
pluginNeed(!
|
|
49106
|
-
if (at ===
|
|
49182
|
+
pluginNeed(isAbsolute11(path) && resolve12(path) === path, "Invalid plugin registry path");
|
|
49183
|
+
for (let at = path;; at = dirname12(at)) {
|
|
49184
|
+
pluginNeed(!lstatSync14(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
49185
|
+
if (at === dirname12(at))
|
|
49107
49186
|
break;
|
|
49108
49187
|
}
|
|
49109
49188
|
}
|
|
49110
49189
|
function readRegistry(path) {
|
|
49111
49190
|
safe3(path);
|
|
49112
|
-
const initial =
|
|
49191
|
+
const initial = lstatSync14(path);
|
|
49113
49192
|
pluginNeed(initial.isFile() && initial.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
|
|
49114
49193
|
const fd = openSync11(path, constants8.O_RDONLY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK);
|
|
49115
49194
|
try {
|
|
@@ -49123,7 +49202,7 @@ function readRegistry(path) {
|
|
|
49123
49202
|
break;
|
|
49124
49203
|
length += count;
|
|
49125
49204
|
}
|
|
49126
|
-
const after = fstatSync11(fd), current =
|
|
49205
|
+
const after = fstatSync11(fd), current = lstatSync14(path);
|
|
49127
49206
|
safe3(path);
|
|
49128
49207
|
pluginNeed(length <= 1024 * 1024 && length === opened.size && after.size === opened.size && after.mtimeMs === opened.mtimeMs && after.ctimeMs === opened.ctimeMs && current.dev === opened.dev && current.ino === opened.ino && current.mtimeMs === opened.mtimeMs && current.ctimeMs === opened.ctimeMs, "Plugin registry changed during read");
|
|
49129
49208
|
let value;
|
|
@@ -49153,7 +49232,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
49153
49232
|
seen.add(target.pluginId);
|
|
49154
49233
|
const rows = plugins[target.pluginId];
|
|
49155
49234
|
pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
|
|
49156
|
-
const [name, market] = target.pluginId.split("@"), cacheRoot =
|
|
49235
|
+
const [name, market] = target.pluginId.split("@"), cacheRoot = join23(dirname12(path), "cache", market, name);
|
|
49157
49236
|
const scopes = new Set, approvals = new Map, currentFiles = new Map;
|
|
49158
49237
|
plugins[target.pluginId] = rows.map((row) => {
|
|
49159
49238
|
pluginNeed(pluginObject(row), "Invalid managed plugin registration");
|
|
@@ -49166,10 +49245,10 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
49166
49245
|
pluginText(row.sourceProducerPath);
|
|
49167
49246
|
pluginText(row.lastUpdated, 64);
|
|
49168
49247
|
pluginNeed(Number.isFinite(Date.parse(row.lastUpdated)), "Invalid managed plugin update timestamp");
|
|
49169
|
-
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath ===
|
|
49248
|
+
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join23(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
49170
49249
|
const approval = (producer) => {
|
|
49171
49250
|
pluginText(producer);
|
|
49172
|
-
const digest = `sha256:${
|
|
49251
|
+
const digest = `sha256:${basename6(producer)}`;
|
|
49173
49252
|
const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest);
|
|
49174
49253
|
pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
|
|
49175
49254
|
if (!verified.has(producer)) {
|
|
@@ -49196,7 +49275,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
49196
49275
|
return Object.fromEntries(Object.entries(row).filter(([key]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key)));
|
|
49197
49276
|
});
|
|
49198
49277
|
safe3(cacheRoot);
|
|
49199
|
-
const before =
|
|
49278
|
+
const before = lstatSync14(cacheRoot);
|
|
49200
49279
|
pluginNeed(before.isDirectory(), "Invalid managed plugin cache root");
|
|
49201
49280
|
const directory = opendirSync3(cacheRoot), names = [];
|
|
49202
49281
|
try {
|
|
@@ -49209,17 +49288,17 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
49209
49288
|
directory.closeSync();
|
|
49210
49289
|
}
|
|
49211
49290
|
for (const version2 of names.sort()) {
|
|
49212
|
-
const files = pluginFileWitnesses(snapshotPluginTree(
|
|
49291
|
+
const files = pluginFileWitnesses(snapshotPluginTree(join23(cacheRoot, version2), { nativeRuntime: `claude-${target.native.version}` }));
|
|
49213
49292
|
verifiedBytes += files.reduce((total, file2) => total + file2.size, 0);
|
|
49214
49293
|
pluginNeed(verifiedBytes <= 256 * 1024 * 1024, "Managed plugin verification exceeds its aggregate byte budget");
|
|
49215
49294
|
const serialized = JSON.stringify(files);
|
|
49216
|
-
const expected = currentFiles.get(
|
|
49295
|
+
const expected = currentFiles.get(join23(cacheRoot, version2));
|
|
49217
49296
|
pluginNeed(expected === undefined || serialized === expected, "Current native cache differs from its exact registered producer receipt");
|
|
49218
49297
|
pluginNeed([...approvals.values()].some((receipt) => nativeVersionMatches(version2, receipt) && JSON.stringify(receipt.plan.files) === serialized), "A retained native plugin cache version differs from every approved projection");
|
|
49219
49298
|
}
|
|
49220
49299
|
for (const row of rows)
|
|
49221
49300
|
pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
|
|
49222
|
-
const after =
|
|
49301
|
+
const after = lstatSync14(cacheRoot);
|
|
49223
49302
|
safe3(cacheRoot);
|
|
49224
49303
|
pluginNeed(before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs, "Managed cache version membership changed during verification");
|
|
49225
49304
|
}
|
|
@@ -49234,30 +49313,30 @@ var init_plugin_discovery = __esm(() => {
|
|
|
49234
49313
|
|
|
49235
49314
|
// src/lib/claude-marketplace-registry.ts
|
|
49236
49315
|
import { createHash as createHash13 } from "crypto";
|
|
49237
|
-
import { closeSync as closeSync12, constants as constants9, fstatSync as fstatSync12, lstatSync as
|
|
49238
|
-
import { basename as
|
|
49316
|
+
import { closeSync as closeSync12, constants as constants9, fstatSync as fstatSync12, lstatSync as lstatSync15, openSync as openSync12, readSync as readSync8 } from "fs";
|
|
49317
|
+
import { basename as basename7, dirname as dirname13, isAbsolute as isAbsolute12, resolve as resolve13 } from "path";
|
|
49239
49318
|
function need5(value, reason) {
|
|
49240
49319
|
if (!value)
|
|
49241
49320
|
throw new Error(`Claude marketplace registry ${reason}`);
|
|
49242
49321
|
}
|
|
49243
49322
|
function absolutePath2(value) {
|
|
49244
|
-
need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute12(value) &&
|
|
49323
|
+
need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute12(value) && resolve13(value) === value, "requires a normalized absolute path");
|
|
49245
49324
|
}
|
|
49246
49325
|
function parents2(path) {
|
|
49247
49326
|
const result = [];
|
|
49248
|
-
for (let at =
|
|
49249
|
-
const stat2 =
|
|
49327
|
+
for (let at = dirname13(path);; at = dirname13(at)) {
|
|
49328
|
+
const stat2 = lstatSync15(at, { bigint: true });
|
|
49250
49329
|
need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
49251
49330
|
result.push([at, stat2]);
|
|
49252
|
-
if (at ===
|
|
49331
|
+
if (at === dirname13(at))
|
|
49253
49332
|
return result;
|
|
49254
49333
|
}
|
|
49255
49334
|
}
|
|
49256
49335
|
function readRegistry2(path, budget) {
|
|
49257
49336
|
absolutePath2(path);
|
|
49258
|
-
need5(
|
|
49337
|
+
need5(basename7(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
49259
49338
|
need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
|
|
49260
|
-
const ancestors2 = parents2(path), initial =
|
|
49339
|
+
const ancestors2 = parents2(path), initial = lstatSync15(path, { bigint: true });
|
|
49261
49340
|
need5(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
49262
49341
|
need5(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
|
|
49263
49342
|
const fd = openSync12(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
|
|
@@ -49272,10 +49351,10 @@ function readRegistry2(path, budget) {
|
|
|
49272
49351
|
break;
|
|
49273
49352
|
length += count;
|
|
49274
49353
|
}
|
|
49275
|
-
const after = fstatSync12(fd, { bigint: true }), current =
|
|
49354
|
+
const after = fstatSync12(fd, { bigint: true }), current = lstatSync15(path, { bigint: true });
|
|
49276
49355
|
need5(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
49277
49356
|
for (const [ancestor, before] of ancestors2) {
|
|
49278
|
-
const now =
|
|
49357
|
+
const now = lstatSync15(ancestor, { bigint: true });
|
|
49279
49358
|
need5(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
49280
49359
|
}
|
|
49281
49360
|
budget.remaining -= length;
|
|
@@ -49415,26 +49494,26 @@ var init_claude_marketplace_registry = __esm(() => {
|
|
|
49415
49494
|
});
|
|
49416
49495
|
|
|
49417
49496
|
// src/lib/codex-hook-trust-files.ts
|
|
49418
|
-
import { closeSync as closeSync13, constants as constants10, fstatSync as fstatSync13, fsyncSync as fsyncSync3, lstatSync as
|
|
49497
|
+
import { closeSync as closeSync13, constants as constants10, fstatSync as fstatSync13, fsyncSync as fsyncSync3, lstatSync as lstatSync16, openSync as openSync13, readSync as readSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
49419
49498
|
import { createHash as createHash14 } from "crypto";
|
|
49420
|
-
import { dirname as
|
|
49499
|
+
import { dirname as dirname14 } from "path";
|
|
49421
49500
|
function need6(value, code) {
|
|
49422
49501
|
if (!value)
|
|
49423
49502
|
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
49424
49503
|
}
|
|
49425
49504
|
function safeParents(file2) {
|
|
49426
|
-
for (let p =
|
|
49427
|
-
const s =
|
|
49505
|
+
for (let p = dirname14(file2);; p = dirname14(p)) {
|
|
49506
|
+
const s = lstatSync16(p);
|
|
49428
49507
|
need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
|
|
49429
49508
|
need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
49430
|
-
if (
|
|
49509
|
+
if (dirname14(p) === p)
|
|
49431
49510
|
break;
|
|
49432
49511
|
}
|
|
49433
49512
|
}
|
|
49434
49513
|
function snapshot(file2, privateFile = false, options = {}) {
|
|
49435
49514
|
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
49436
49515
|
safeParents(file2);
|
|
49437
|
-
const initial =
|
|
49516
|
+
const initial = lstatSync16(file2, { bigint: true });
|
|
49438
49517
|
need6(initial.isFile() && initial.uid === BigInt(process.getuid()) && (initial.nlink === 1n || readOnlyPackage && initial.nlink > 1n) && (initial.mode & 0o022n) === 0n && (!privateFile || (initial.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
|
|
49439
49518
|
need6(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
49440
49519
|
const fd = openSync13(file2, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
@@ -49449,7 +49528,7 @@ function snapshot(file2, privateFile = false, options = {}) {
|
|
|
49449
49528
|
break;
|
|
49450
49529
|
length += n2;
|
|
49451
49530
|
}
|
|
49452
|
-
need6(length === Number(before.size) && sameStat(before, fstatSync13(fd, { bigint: true })) && sameStat(before,
|
|
49531
|
+
need6(length === Number(before.size) && sameStat(before, fstatSync13(fd, { bigint: true })) && sameStat(before, lstatSync16(file2, { bigint: true })), "INPUT_CHANGED");
|
|
49453
49532
|
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
49454
49533
|
return { file: file2, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash14("sha256").update(content).digest("hex") };
|
|
49455
49534
|
} finally {
|
|
@@ -49504,8 +49583,8 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
49504
49583
|
|
|
49505
49584
|
// src/lib/agent-discovery.ts
|
|
49506
49585
|
import { createHash as createHash16 } from "crypto";
|
|
49507
|
-
import { lstatSync as
|
|
49508
|
-
import { basename as
|
|
49586
|
+
import { lstatSync as lstatSync17, readFileSync as readFileSync15, readdirSync as readdirSync7, realpathSync as realpathSync4 } from "fs";
|
|
49587
|
+
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute13, join as join24, resolve as resolve14, sep as sep5 } from "path";
|
|
49509
49588
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
49510
49589
|
function parseConfig(text2, path, toml = false) {
|
|
49511
49590
|
try {
|
|
@@ -49520,10 +49599,10 @@ function parseConfig(text2, path, toml = false) {
|
|
|
49520
49599
|
function safe4(path) {
|
|
49521
49600
|
if (!isAbsolute13(path) || path.includes("\x00"))
|
|
49522
49601
|
throw new Error("Expected an absolute native discovery path");
|
|
49523
|
-
for (let cursor = path;; cursor =
|
|
49524
|
-
if (
|
|
49602
|
+
for (let cursor = path;; cursor = dirname15(cursor)) {
|
|
49603
|
+
if (lstatSync17(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
49525
49604
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
49526
|
-
if (
|
|
49605
|
+
if (dirname15(cursor) === cursor)
|
|
49527
49606
|
break;
|
|
49528
49607
|
}
|
|
49529
49608
|
}
|
|
@@ -49531,7 +49610,7 @@ function read(path, changes) {
|
|
|
49531
49610
|
safe4(path);
|
|
49532
49611
|
if (changes?.has(path))
|
|
49533
49612
|
return changes.get(path);
|
|
49534
|
-
const stat2 =
|
|
49613
|
+
const stat2 = lstatSync17(path, { throwIfNoEntry: false });
|
|
49535
49614
|
if (!stat2)
|
|
49536
49615
|
return null;
|
|
49537
49616
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
@@ -49605,8 +49684,16 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
49605
49684
|
throw new Error("Invalid native discovery binding");
|
|
49606
49685
|
if (binding.agent === "hermes" && !binding.directories?.length)
|
|
49607
49686
|
throw new Error("Hermes discovery requires directory membership coverage; run skills hook install with a fresh discovery review");
|
|
49608
|
-
|
|
49609
|
-
|
|
49687
|
+
const installationRoots = codexInstallationRoots(binding);
|
|
49688
|
+
const installationInput = (path) => installationRoots.some((root) => path === root || path.startsWith(root + sep5));
|
|
49689
|
+
if (binding.directories !== undefined) {
|
|
49690
|
+
const projected2 = binding.codexInstallationInputs?.directories ?? [];
|
|
49691
|
+
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root) => root.startsWith(directory.path + sep5)));
|
|
49692
|
+
if (projected2.length !== ancestors2.length || projected2.some((directory) => !ancestors2.some((original) => original.path === directory.path)))
|
|
49693
|
+
throw new Error("Missing installation input directory projection");
|
|
49694
|
+
verifyDiscoveryDirectories(binding.directories.filter((directory) => !installationInput(directory.path) && !ancestors2.includes(directory)));
|
|
49695
|
+
verifyDiscoveryDirectories(projected2, installationRoots);
|
|
49696
|
+
}
|
|
49610
49697
|
const budget = discoveryByteBudget();
|
|
49611
49698
|
for (const source of binding.sources) {
|
|
49612
49699
|
assertMarketplaceBinding(binding, source);
|
|
@@ -49616,6 +49703,10 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
49616
49703
|
throw new Error("Invalid native discovery projection");
|
|
49617
49704
|
if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
49618
49705
|
throw new Error("Invalid native discovery digest");
|
|
49706
|
+
if (installationInput(source.path)) {
|
|
49707
|
+
safe4(source.path);
|
|
49708
|
+
continue;
|
|
49709
|
+
}
|
|
49619
49710
|
const current = projected(source, undefined, budget);
|
|
49620
49711
|
if (current !== source.sha256 && !verifiesCodexHookDiscoverySource(binding, source, current, codexRecovery))
|
|
49621
49712
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
@@ -49623,19 +49714,40 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
49623
49714
|
for (const root of binding.roots)
|
|
49624
49715
|
safe4(root);
|
|
49625
49716
|
}
|
|
49717
|
+
function codexInstallationRoots(binding) {
|
|
49718
|
+
const proof = binding.codexInstallationInputs;
|
|
49719
|
+
if (proof === undefined)
|
|
49720
|
+
return [];
|
|
49721
|
+
if (binding.agent !== "codex" || binding.method !== "reviewed" || proof.version !== "codex-cli 0.160.0" || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
|
|
49722
|
+
throw new Error("Invalid native installation input proof");
|
|
49723
|
+
const cache = dirname15(dirname15(proof.plugins[0].pluginParent));
|
|
49724
|
+
const config2 = join24(dirname15(dirname15(cache)), "config.toml"), home = dirname15(dirname15(dirname15(cache)));
|
|
49725
|
+
const configSource = binding.sources.find((source) => source.path === config2 && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
49726
|
+
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join24(home, path));
|
|
49727
|
+
if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot + sep5) || input2.sourceRoot.startsWith(root + sep5)) || binding.sources.some((source) => basename8(source.path) === "config.toml" && (source.path === input2.sourceRoot || source.path.startsWith(input2.sourceRoot + sep5)))))
|
|
49728
|
+
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
49729
|
+
if (proof.plugins.some((input2) => dirname15(dirname15(input2.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join24(input2.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
49730
|
+
throw new Error("Missing native installation input source witness");
|
|
49731
|
+
return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
|
|
49732
|
+
const text2 = read(path);
|
|
49733
|
+
if (text2 === null)
|
|
49734
|
+
throw new Error("Missing native installation input");
|
|
49735
|
+
return text2;
|
|
49736
|
+
});
|
|
49737
|
+
}
|
|
49626
49738
|
function assertMarketplaceBinding(binding, source) {
|
|
49627
|
-
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" ||
|
|
49739
|
+
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename8(source.path) !== "config.toml"))
|
|
49628
49740
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
49629
|
-
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" ||
|
|
49741
|
+
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
|
|
49630
49742
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
49631
49743
|
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
49632
49744
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
49633
49745
|
}
|
|
49634
49746
|
function agentDiscoveryConfigPath(home, agent) {
|
|
49635
|
-
return
|
|
49747
|
+
return join24(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
49636
49748
|
}
|
|
49637
49749
|
function resolveAgentDiscovery(options) {
|
|
49638
|
-
const canonical6 = options.canonical ??
|
|
49750
|
+
const canonical6 = options.canonical ?? resolve14, home = resolve14(options.home), agent = options.agent;
|
|
49639
49751
|
const sources = [], roots = new Set, builtinNames = [];
|
|
49640
49752
|
const witness = (path, format, fields2) => {
|
|
49641
49753
|
const source = { path: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
|
|
@@ -49652,7 +49764,7 @@ function resolveAgentDiscovery(options) {
|
|
|
49652
49764
|
throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
|
|
49653
49765
|
};
|
|
49654
49766
|
if (agent === "hermes") {
|
|
49655
|
-
const profile = witness(
|
|
49767
|
+
const profile = witness(join24(home, ".hermes/active_profile"));
|
|
49656
49768
|
if (profile?.trim() && profile.trim() !== "default")
|
|
49657
49769
|
unresolved("a non-default profile is active");
|
|
49658
49770
|
const declared = config2.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
|
|
@@ -49666,7 +49778,7 @@ function resolveAgentDiscovery(options) {
|
|
|
49666
49778
|
continue;
|
|
49667
49779
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
49668
49780
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
49669
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ?
|
|
49781
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join24(home, normalized.slice(2)) : resolve14(home, ".hermes", normalized);
|
|
49670
49782
|
safe4(path);
|
|
49671
49783
|
roots.add(path);
|
|
49672
49784
|
}
|
|
@@ -49675,24 +49787,24 @@ function resolveAgentDiscovery(options) {
|
|
|
49675
49787
|
const executable = Bun.which("gemini");
|
|
49676
49788
|
if (executable) {
|
|
49677
49789
|
let packageRoot;
|
|
49678
|
-
for (let directory =
|
|
49679
|
-
const path =
|
|
49790
|
+
for (let directory = dirname15(realpathSync4(executable)), depth = 0;depth < 8; directory = dirname15(directory), depth++) {
|
|
49791
|
+
const path = join24(directory, "package.json"), raw = read(path);
|
|
49680
49792
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
49681
49793
|
packageRoot = directory;
|
|
49682
49794
|
witness(path);
|
|
49683
49795
|
break;
|
|
49684
49796
|
}
|
|
49685
|
-
if (
|
|
49797
|
+
if (dirname15(directory) === directory)
|
|
49686
49798
|
break;
|
|
49687
49799
|
}
|
|
49688
49800
|
if (!packageRoot)
|
|
49689
49801
|
unresolved("installed Gemini package layout is not recognized");
|
|
49690
|
-
const builtinRoot =
|
|
49802
|
+
const builtinRoot = join24(packageRoot, "bundle/builtin");
|
|
49691
49803
|
safe4(builtinRoot);
|
|
49692
|
-
if (!
|
|
49804
|
+
if (!lstatSync17(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
49693
49805
|
unresolved("installed Gemini builtin root is missing");
|
|
49694
|
-
for (const name of
|
|
49695
|
-
const text2 = witness(
|
|
49806
|
+
for (const name of readdirSync7(builtinRoot).sort()) {
|
|
49807
|
+
const text2 = witness(join24(builtinRoot, name, "SKILL.md"));
|
|
49696
49808
|
const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
|
|
49697
49809
|
if (!match?.[1] || builtinNames.includes(match[1]))
|
|
49698
49810
|
unresolved("installed Gemini builtin name is missing or ambiguous");
|
|
@@ -49734,39 +49846,39 @@ function resolveAgentDiscovery(options) {
|
|
|
49734
49846
|
function plugin(root) {
|
|
49735
49847
|
root = canonical6(root);
|
|
49736
49848
|
safe4(root);
|
|
49737
|
-
const manifestPath =
|
|
49849
|
+
const manifestPath = join24(root, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
49738
49850
|
const raw = witness(manifestPath);
|
|
49739
49851
|
if (raw === null)
|
|
49740
49852
|
unresolved("plugin manifest missing");
|
|
49741
49853
|
const manifest = parseConfig(raw, manifestPath);
|
|
49742
|
-
const hooks = witness(
|
|
49854
|
+
const hooks = witness(join24(root, "hooks/hooks.json"));
|
|
49743
49855
|
if (manifest.hooks !== undefined || hooks !== null)
|
|
49744
49856
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
49745
|
-
const commands =
|
|
49857
|
+
const commands = join24(root, "commands");
|
|
49746
49858
|
safe4(commands);
|
|
49747
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
49859
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length))
|
|
49748
49860
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
49749
|
-
const rootSkill = witness(
|
|
49861
|
+
const rootSkill = witness(join24(root, "SKILL.md"));
|
|
49750
49862
|
if (rootSkill !== null)
|
|
49751
49863
|
roots.add(root);
|
|
49752
49864
|
const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
49753
49865
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
49754
49866
|
unresolved("unsupported plugin skill paths");
|
|
49755
49867
|
if (agent === "claude")
|
|
49756
|
-
roots.add(
|
|
49868
|
+
roots.add(join24(root, "skills"));
|
|
49757
49869
|
for (const value of declared) {
|
|
49758
|
-
const path =
|
|
49759
|
-
if (path !== root && !path.startsWith(root +
|
|
49870
|
+
const path = resolve14(root, value);
|
|
49871
|
+
if (path !== root && !path.startsWith(root + sep5))
|
|
49760
49872
|
unresolved("plugin skill path escapes its root");
|
|
49761
|
-
roots.add(path.endsWith(`${
|
|
49873
|
+
roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname15(path) : path);
|
|
49762
49874
|
}
|
|
49763
49875
|
}
|
|
49764
49876
|
if (agent === "claude") {
|
|
49765
|
-
const registrations = witness(
|
|
49766
|
-
const installed = registrations === null ? {} : parseConfig(registrations,
|
|
49767
|
-
const commands = canonical6(
|
|
49877
|
+
const registrations = witness(join24(home, ".claude/plugins/installed_plugins.json"));
|
|
49878
|
+
const installed = registrations === null ? {} : parseConfig(registrations, join24(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
49879
|
+
const commands = canonical6(join24(home, ".claude/commands"));
|
|
49768
49880
|
safe4(commands);
|
|
49769
|
-
if (
|
|
49881
|
+
if (lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
|
|
49770
49882
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
49771
49883
|
for (const [id, enabled] of Object.entries(config2.enabledPlugins ?? {})) {
|
|
49772
49884
|
if (enabled === false)
|
|
@@ -49788,16 +49900,16 @@ function resolveAgentDiscovery(options) {
|
|
|
49788
49900
|
const market = config2.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
49789
49901
|
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute13(market.source))
|
|
49790
49902
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
49791
|
-
const catalogText = witness(
|
|
49903
|
+
const catalogText = witness(join24(market.source, ".agents/plugins/marketplace.json"));
|
|
49792
49904
|
if (catalogText === null)
|
|
49793
49905
|
unresolved("marketplace catalog missing");
|
|
49794
|
-
const catalog = parseConfig(catalogText,
|
|
49906
|
+
const catalog = parseConfig(catalogText, join24(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
49795
49907
|
if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
|
|
49796
49908
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
49797
|
-
plugin(
|
|
49909
|
+
plugin(resolve14(market.source, matches[0].source.path));
|
|
49798
49910
|
}
|
|
49799
49911
|
} else if (agent === "opencode") {
|
|
49800
|
-
if (witness(
|
|
49912
|
+
if (witness(join24(home, ".config/opencode/opencode.jsonc")) !== null || witness(join24(home, ".config/opencode/config.json")) !== null)
|
|
49801
49913
|
unresolved("additional config layers require review");
|
|
49802
49914
|
if ((config2.plugin?.length ?? 0) > 0 || config2.skills?.urls?.length)
|
|
49803
49915
|
unresolved("external plugin or remote skill source");
|
|
@@ -49806,14 +49918,14 @@ function resolveAgentDiscovery(options) {
|
|
|
49806
49918
|
unresolved("relative or malformed added skill root");
|
|
49807
49919
|
roots.add(path);
|
|
49808
49920
|
}
|
|
49809
|
-
const localPlugins =
|
|
49921
|
+
const localPlugins = join24(home, ".config/opencode/plugins");
|
|
49810
49922
|
safe4(localPlugins);
|
|
49811
|
-
if (
|
|
49923
|
+
if (lstatSync17(localPlugins, { throwIfNoEntry: false }) && readdirSync7(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
49812
49924
|
unresolved("additional local plugin hooks require review");
|
|
49813
49925
|
} else if (agent === "hermes") {
|
|
49814
|
-
for (const directory of [
|
|
49926
|
+
for (const directory of [join24(home, ".hermes/plugins"), join24(home, ".hermes/hermes-agent")]) {
|
|
49815
49927
|
safe4(directory);
|
|
49816
|
-
if (
|
|
49928
|
+
if (lstatSync17(directory, { throwIfNoEntry: false }))
|
|
49817
49929
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
49818
49930
|
}
|
|
49819
49931
|
if (Bun.which("hermes") || Object.keys(config2.plugins ?? {}).length)
|
|
@@ -49821,24 +49933,24 @@ function resolveAgentDiscovery(options) {
|
|
|
49821
49933
|
} else if (agent === "gemini") {
|
|
49822
49934
|
if (Object.keys(config2.extensions ?? {}).length || config2.skills?.paths?.length)
|
|
49823
49935
|
unresolved("custom extension or skill paths");
|
|
49824
|
-
const directory =
|
|
49936
|
+
const directory = join24(home, ".gemini/extensions");
|
|
49825
49937
|
safe4(directory);
|
|
49826
|
-
if (
|
|
49827
|
-
for (const name of
|
|
49828
|
-
const root =
|
|
49938
|
+
if (lstatSync17(directory, { throwIfNoEntry: false }))
|
|
49939
|
+
for (const name of readdirSync7(directory)) {
|
|
49940
|
+
const root = join24(directory, name);
|
|
49829
49941
|
safe4(root);
|
|
49830
|
-
if (!
|
|
49942
|
+
if (!lstatSync17(root)?.isDirectory())
|
|
49831
49943
|
continue;
|
|
49832
|
-
const raw = witness(
|
|
49944
|
+
const raw = witness(join24(root, "gemini-extension.json"));
|
|
49833
49945
|
if (raw === null)
|
|
49834
49946
|
unresolved("extension registration missing");
|
|
49835
|
-
const manifest = parseConfig(raw,
|
|
49836
|
-
if (manifest.hooks !== undefined || witness(
|
|
49947
|
+
const manifest = parseConfig(raw, join24(root, "gemini-extension.json"));
|
|
49948
|
+
if (manifest.hooks !== undefined || witness(join24(root, "hooks/hooks.json")) !== null || witness(join24(root, ".gemini-extension-install.json")) !== null)
|
|
49837
49949
|
unresolved("extension hooks or linked registration require review");
|
|
49838
|
-
roots.add(
|
|
49950
|
+
roots.add(join24(root, "skills"));
|
|
49839
49951
|
}
|
|
49840
49952
|
}
|
|
49841
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([
|
|
49953
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join24(home, ".hermes/plugins"), join24(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
|
|
49842
49954
|
}
|
|
49843
49955
|
var digest = (text2) => createHash16("sha256").update(text2).digest("hex");
|
|
49844
49956
|
var init_agent_discovery = __esm(() => {
|
|
@@ -49853,15 +49965,17 @@ var init_agent_discovery = __esm(() => {
|
|
|
49853
49965
|
init_claude_settings_witness();
|
|
49854
49966
|
init_codex_hook_discovery_recovery();
|
|
49855
49967
|
init_codex_settings_witness();
|
|
49968
|
+
init_codex_plugin_skill_controls();
|
|
49969
|
+
init_native_discovery_roots();
|
|
49856
49970
|
init_agent_discovery_directories();
|
|
49857
49971
|
});
|
|
49858
49972
|
|
|
49859
49973
|
// src/lib/authoring-path.ts
|
|
49860
|
-
import { lstatSync as
|
|
49974
|
+
import { lstatSync as lstatSync18, realpathSync as realpathSync5 } from "fs";
|
|
49861
49975
|
import { homedir as homedir3 } from "os";
|
|
49862
|
-
import { basename as
|
|
49976
|
+
import { basename as basename9, dirname as dirname16, join as join25, resolve as resolve15, sep as sep6 } from "path";
|
|
49863
49977
|
function pathParts(path) {
|
|
49864
|
-
return
|
|
49978
|
+
return resolve15(path).split(sep6).filter(Boolean);
|
|
49865
49979
|
}
|
|
49866
49980
|
function nativeRootMatch(path) {
|
|
49867
49981
|
const parts = pathParts(path);
|
|
@@ -49875,24 +49989,24 @@ function nativeRootMatch(path) {
|
|
|
49875
49989
|
return;
|
|
49876
49990
|
}
|
|
49877
49991
|
function physicalPath(path) {
|
|
49878
|
-
let cursor =
|
|
49992
|
+
let cursor = resolve15(path);
|
|
49879
49993
|
const suffix = [];
|
|
49880
|
-
while (!
|
|
49881
|
-
suffix.unshift(
|
|
49882
|
-
const parent =
|
|
49994
|
+
while (!lstatSync18(cursor, { throwIfNoEntry: false })) {
|
|
49995
|
+
suffix.unshift(basename9(cursor));
|
|
49996
|
+
const parent = dirname16(cursor);
|
|
49883
49997
|
if (parent === cursor)
|
|
49884
|
-
return
|
|
49998
|
+
return resolve15(path);
|
|
49885
49999
|
cursor = parent;
|
|
49886
50000
|
}
|
|
49887
|
-
return
|
|
50001
|
+
return resolve15(realpathSync5(cursor), ...suffix);
|
|
49888
50002
|
}
|
|
49889
50003
|
function contains(root, path) {
|
|
49890
|
-
return path === root || path.startsWith(root +
|
|
50004
|
+
return path === root || path.startsWith(root + sep6);
|
|
49891
50005
|
}
|
|
49892
50006
|
function configuredRoots(home, explicitHome) {
|
|
49893
|
-
const homeData =
|
|
50007
|
+
const homeData = join25(home, ".hasna", "skills");
|
|
49894
50008
|
const homePolicy = readManagedSkillPolicySnapshot(homeData);
|
|
49895
|
-
const configuredPolicy = !explicitHome &&
|
|
50009
|
+
const configuredPolicy = !explicitHome && resolve15(getDataDirReadOnly()) !== resolve15(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
|
|
49896
50010
|
const policy = homePolicy ?? configuredPolicy;
|
|
49897
50011
|
const bridge = policy?.value.bridge;
|
|
49898
50012
|
if (bridge && (typeof bridge.home !== "string" || physicalPath(bridge.home) !== physicalPath(home))) {
|
|
@@ -49921,8 +50035,8 @@ function configuredRoots(home, explicitHome) {
|
|
|
49921
50035
|
admitBinding(binding);
|
|
49922
50036
|
continue;
|
|
49923
50037
|
}
|
|
49924
|
-
const nativeHome =
|
|
49925
|
-
if (!
|
|
50038
|
+
const nativeHome = join25(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
|
|
50039
|
+
if (!lstatSync18(nativeHome, { throwIfNoEntry: false }))
|
|
49926
50040
|
continue;
|
|
49927
50041
|
roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
|
|
49928
50042
|
}
|
|
@@ -49931,22 +50045,22 @@ function configuredRoots(home, explicitHome) {
|
|
|
49931
50045
|
function assertPortableAuthoringPath(path, options = {}) {
|
|
49932
50046
|
if (typeof path !== "string" || !path || path.includes("\x00"))
|
|
49933
50047
|
throw new Error("Invalid portable authoring path");
|
|
49934
|
-
const lexical =
|
|
50048
|
+
const lexical = resolve15(path);
|
|
49935
50049
|
const physical = physicalPath(lexical);
|
|
49936
50050
|
const candidates = [lexical, physical];
|
|
49937
50051
|
let native = candidates.map(nativeRootMatch).find(Boolean);
|
|
49938
|
-
const home =
|
|
49939
|
-
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) =>
|
|
49940
|
-
defaults.push(
|
|
50052
|
+
const home = resolve15(options.homeDir ?? homedir3());
|
|
50053
|
+
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join25(home, ...parts));
|
|
50054
|
+
defaults.push(join25(home, ".codex/plugins/cache"), join25(home, ".claude/plugins/cache"), join25(home, ".claude/plugins/synced"), join25(home, ".gemini/extensions"));
|
|
49941
50055
|
for (const root of defaults) {
|
|
49942
|
-
if (candidates.some((candidate) => contains(
|
|
50056
|
+
if (candidates.some((candidate) => contains(resolve15(root), candidate) || contains(physicalPath(root), candidate)))
|
|
49943
50057
|
native ??= root;
|
|
49944
50058
|
}
|
|
49945
50059
|
if (native) {
|
|
49946
50060
|
throw new Error(`Refusing portable Skills authoring below native discovery root '${native}': ${lexical}. Set HASNA_SKILLS_DIR to a private authoring corpus outside native roots.`);
|
|
49947
50061
|
}
|
|
49948
50062
|
for (const root of configuredRoots(home, options.homeDir !== undefined)) {
|
|
49949
|
-
if (candidates.some((candidate) => contains(
|
|
50063
|
+
if (candidates.some((candidate) => contains(resolve15(root), candidate) || contains(physicalPath(root), candidate))) {
|
|
49950
50064
|
throw new Error(`Refusing portable Skills authoring below configured native discovery root: ${lexical}`);
|
|
49951
50065
|
}
|
|
49952
50066
|
}
|
|
@@ -49966,29 +50080,29 @@ import {
|
|
|
49966
50080
|
existsSync as existsSync11,
|
|
49967
50081
|
mkdirSync as mkdirSync7,
|
|
49968
50082
|
mkdtempSync,
|
|
49969
|
-
readdirSync as
|
|
49970
|
-
realpathSync as
|
|
50083
|
+
readdirSync as readdirSync8,
|
|
50084
|
+
realpathSync as realpathSync6,
|
|
49971
50085
|
renameSync as renameSync3,
|
|
49972
50086
|
rmSync as rmSync3,
|
|
49973
50087
|
statSync as statSync7,
|
|
49974
50088
|
writeFileSync as writeFileSync6
|
|
49975
50089
|
} from "fs";
|
|
49976
|
-
import { basename as
|
|
50090
|
+
import { basename as basename10, dirname as dirname17, isAbsolute as isAbsolute14, join as join26, normalize as normalize3, relative as relative5, resolve as resolve16, sep as sep7 } from "path";
|
|
49977
50091
|
function getPortableSkillsRoot(options = {}) {
|
|
49978
50092
|
return resolvePortableSkillsRoot(options, true);
|
|
49979
50093
|
}
|
|
49980
50094
|
function resolvePortableSkillsRoot(options, migrate) {
|
|
49981
50095
|
if (options.rootDir)
|
|
49982
50096
|
return options.rootDir;
|
|
49983
|
-
const appDir = options.homeDir ?
|
|
49984
|
-
const cache =
|
|
50097
|
+
const appDir = options.homeDir ? join26(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
|
|
50098
|
+
const cache = join26(appDir, SKILLS_CACHE_DIRNAME);
|
|
49985
50099
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
|
|
49986
50100
|
return cache;
|
|
49987
|
-
const installed =
|
|
50101
|
+
const installed = join26(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
49988
50102
|
return installed;
|
|
49989
50103
|
}
|
|
49990
50104
|
function getPortableSkillPath(name, options = {}) {
|
|
49991
|
-
return
|
|
50105
|
+
return join26(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
49992
50106
|
}
|
|
49993
50107
|
function findPortableSkill(name, options = {}) {
|
|
49994
50108
|
let normalized;
|
|
@@ -50011,10 +50125,10 @@ function listPortableSkills(options = {}) {
|
|
|
50011
50125
|
if (!safeIsDirectory(root))
|
|
50012
50126
|
return [];
|
|
50013
50127
|
const skills = [];
|
|
50014
|
-
for (const entry of
|
|
50128
|
+
for (const entry of readdirSync8(root).sort()) {
|
|
50015
50129
|
if (entry.startsWith("."))
|
|
50016
50130
|
continue;
|
|
50017
|
-
const path =
|
|
50131
|
+
const path = join26(root, entry);
|
|
50018
50132
|
if (!safeIsDirectory(path))
|
|
50019
50133
|
continue;
|
|
50020
50134
|
try {
|
|
@@ -50047,9 +50161,9 @@ function isOfficialSkillName(name) {
|
|
|
50047
50161
|
function scaffoldPortableSkill(name, options = {}) {
|
|
50048
50162
|
const skillName = normalizeNewPortableSkillName(name);
|
|
50049
50163
|
const readOnlyRoot = resolvePortableSkillsRoot(options, false);
|
|
50050
|
-
assertPortableAuthoringPath(
|
|
50164
|
+
assertPortableAuthoringPath(join26(readOnlyRoot, skillName), options);
|
|
50051
50165
|
const root = getPortableSkillsRoot(options);
|
|
50052
|
-
const skillPath =
|
|
50166
|
+
const skillPath = join26(root, skillName);
|
|
50053
50167
|
assertPortableAuthoringPath(skillPath, options);
|
|
50054
50168
|
if (existsSync11(skillPath)) {
|
|
50055
50169
|
if (!options.overwrite)
|
|
@@ -50068,20 +50182,20 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
50068
50182
|
return { name: skillName, path: skillPath, manifest, created: true };
|
|
50069
50183
|
}
|
|
50070
50184
|
function physicalImportPath(path) {
|
|
50071
|
-
let ancestor =
|
|
50185
|
+
let ancestor = resolve16(path);
|
|
50072
50186
|
const suffix = [];
|
|
50073
50187
|
while (!existsSync11(ancestor)) {
|
|
50074
|
-
suffix.unshift(
|
|
50075
|
-
ancestor =
|
|
50188
|
+
suffix.unshift(basename10(ancestor));
|
|
50189
|
+
ancestor = dirname17(ancestor);
|
|
50076
50190
|
}
|
|
50077
|
-
return
|
|
50191
|
+
return join26(realpathSync6(ancestor), ...suffix);
|
|
50078
50192
|
}
|
|
50079
50193
|
function assertDisjointImportPaths(source, destination) {
|
|
50080
|
-
const sourcePath =
|
|
50194
|
+
const sourcePath = realpathSync6(source);
|
|
50081
50195
|
const destinationPath = physicalImportPath(destination);
|
|
50082
50196
|
const contains2 = (parent, child) => {
|
|
50083
|
-
const path =
|
|
50084
|
-
return path === "" || !isAbsolute14(path) && path !== ".." && !path.startsWith(`..${
|
|
50197
|
+
const path = relative5(parent, child);
|
|
50198
|
+
return path === "" || !isAbsolute14(path) && path !== ".." && !path.startsWith(`..${sep7}`);
|
|
50085
50199
|
};
|
|
50086
50200
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
50087
50201
|
throw new Error("Source and destination skill directories must not overlap");
|
|
@@ -50096,15 +50210,15 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
50096
50210
|
const explicitName = options.name != null;
|
|
50097
50211
|
const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
|
|
50098
50212
|
if (isOfficialSkillName(skillName) && !options.allowShadow) {
|
|
50099
|
-
const sourceSlug = safeNormalizeName(
|
|
50100
|
-
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${
|
|
50213
|
+
const sourceSlug = safeNormalizeName(basename10(absoluteSource));
|
|
50214
|
+
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename10(absoluteSource)}')` : ""} matches a bundled official skill.`;
|
|
50101
50215
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
50102
50216
|
}
|
|
50103
|
-
const readOnlyDestination =
|
|
50217
|
+
const readOnlyDestination = join26(resolvePortableSkillsRoot(options, false), skillName);
|
|
50104
50218
|
assertPortableAuthoringPath(readOnlyDestination, options);
|
|
50105
50219
|
assertDisjointImportPaths(absoluteSource, readOnlyDestination);
|
|
50106
50220
|
const root = getPortableSkillsRoot(options);
|
|
50107
|
-
const destination =
|
|
50221
|
+
const destination = join26(root, skillName);
|
|
50108
50222
|
assertPortableAuthoringPath(destination, options);
|
|
50109
50223
|
assertDisjointImportPaths(absoluteSource, destination);
|
|
50110
50224
|
if (existsSync11(destination)) {
|
|
@@ -50112,7 +50226,7 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
50112
50226
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
50113
50227
|
rmSync3(destination, { recursive: true, force: true });
|
|
50114
50228
|
}
|
|
50115
|
-
mkdirSync7(
|
|
50229
|
+
mkdirSync7(dirname17(destination), { recursive: true });
|
|
50116
50230
|
copySkillDirectory(absoluteSource, destination);
|
|
50117
50231
|
const base = {
|
|
50118
50232
|
...inferred,
|
|
@@ -50136,8 +50250,8 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
50136
50250
|
const warnings = [...base.warnings];
|
|
50137
50251
|
let manifest;
|
|
50138
50252
|
if (existsSync11(skillPath)) {
|
|
50139
|
-
const skillJsonPath =
|
|
50140
|
-
const skillMdPath =
|
|
50253
|
+
const skillJsonPath = join26(skillPath, "skill.json");
|
|
50254
|
+
const skillMdPath = join26(skillPath, "SKILL.md");
|
|
50141
50255
|
if (!existsSync11(skillJsonPath) && !existsSync11(skillMdPath)) {
|
|
50142
50256
|
add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
50143
50257
|
}
|
|
@@ -50157,7 +50271,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
50157
50271
|
add3(issues, "portable.version_missing", "Portable manifest missing version");
|
|
50158
50272
|
}
|
|
50159
50273
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
50160
|
-
strict: existsSync11(
|
|
50274
|
+
strict: existsSync11(join26(skillPath, "skill.json")),
|
|
50161
50275
|
skillPath
|
|
50162
50276
|
});
|
|
50163
50277
|
for (const issue2 of contractIssues)
|
|
@@ -50197,7 +50311,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
50197
50311
|
add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
50198
50312
|
continue;
|
|
50199
50313
|
}
|
|
50200
|
-
const entryPath =
|
|
50314
|
+
const entryPath = join26(skillPath, command.entry);
|
|
50201
50315
|
if (!existsSync11(entryPath))
|
|
50202
50316
|
add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
50203
50317
|
else if (statSync7(entryPath).isDirectory())
|
|
@@ -50208,7 +50322,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
50208
50322
|
} catch (error61) {
|
|
50209
50323
|
add3(issues, "portable.manifest_invalid", error61.message);
|
|
50210
50324
|
}
|
|
50211
|
-
if (manifest?.kind !== "instruction" && !existsSync11(
|
|
50325
|
+
if (manifest?.kind !== "instruction" && !existsSync11(join26(skillPath, "AGENTS.md"))) {
|
|
50212
50326
|
add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
50213
50327
|
}
|
|
50214
50328
|
}
|
|
@@ -50435,8 +50549,8 @@ var init_search = __esm(() => {
|
|
|
50435
50549
|
});
|
|
50436
50550
|
|
|
50437
50551
|
// src/lib/registry.ts
|
|
50438
|
-
import { existsSync as existsSync12, readFileSync as readFileSync16, readdirSync as
|
|
50439
|
-
import { join as
|
|
50552
|
+
import { existsSync as existsSync12, readFileSync as readFileSync16, readdirSync as readdirSync9 } from "fs";
|
|
50553
|
+
import { join as join27 } from "path";
|
|
50440
50554
|
function parseSkillMdFrontmatter(content) {
|
|
50441
50555
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
50442
50556
|
if (!match)
|
|
@@ -50473,11 +50587,11 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
50473
50587
|
return [];
|
|
50474
50588
|
const result = [];
|
|
50475
50589
|
try {
|
|
50476
|
-
const entries =
|
|
50590
|
+
const entries = readdirSync9(dir, { withFileTypes: true });
|
|
50477
50591
|
for (const entry of entries) {
|
|
50478
50592
|
if (!entry.isDirectory())
|
|
50479
50593
|
continue;
|
|
50480
|
-
const skillMdPath =
|
|
50594
|
+
const skillMdPath = join27(dir, entry.name, "SKILL.md");
|
|
50481
50595
|
if (!existsSync12(skillMdPath))
|
|
50482
50596
|
continue;
|
|
50483
50597
|
let content;
|
|
@@ -50497,7 +50611,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
50497
50611
|
category: fm.category || "Development Tools",
|
|
50498
50612
|
tags: fm.tags || [],
|
|
50499
50613
|
...fm.kind ? { kind: fm.kind } : {},
|
|
50500
|
-
...isHostedMetadataSkillDir(
|
|
50614
|
+
...isHostedMetadataSkillDir(join27(dir, entry.name)) ? { serverOwned: true } : {},
|
|
50501
50615
|
source
|
|
50502
50616
|
});
|
|
50503
50617
|
}
|
|
@@ -50509,12 +50623,12 @@ function findExtensionSkillPath(name) {
|
|
|
50509
50623
|
if (!config2.extensionsDir || !existsSync12(config2.extensionsDir))
|
|
50510
50624
|
return null;
|
|
50511
50625
|
try {
|
|
50512
|
-
const entries =
|
|
50626
|
+
const entries = readdirSync9(config2.extensionsDir, { withFileTypes: true });
|
|
50513
50627
|
for (const entry of entries) {
|
|
50514
50628
|
if (!entry.isDirectory())
|
|
50515
50629
|
continue;
|
|
50516
|
-
const skillDir =
|
|
50517
|
-
const skillMdPath =
|
|
50630
|
+
const skillDir = join27(config2.extensionsDir, entry.name);
|
|
50631
|
+
const skillMdPath = join27(skillDir, "SKILL.md");
|
|
50518
50632
|
if (!existsSync12(skillMdPath))
|
|
50519
50633
|
continue;
|
|
50520
50634
|
let content;
|
|
@@ -51712,13 +51826,13 @@ var init_remote_workspace_leave = __esm(() => {
|
|
|
51712
51826
|
|
|
51713
51827
|
// src/lib/auth-store.ts
|
|
51714
51828
|
import { chmodSync, existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync17, renameSync as renameSync4, statSync as statSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
51715
|
-
import { basename as
|
|
51829
|
+
import { basename as basename11, dirname as dirname18, join as join28 } from "path";
|
|
51716
51830
|
function getAuthFilePath(env = process.env) {
|
|
51717
51831
|
return skillsCredentialFilePath(env);
|
|
51718
51832
|
}
|
|
51719
51833
|
function getIdentityFilePath(env = process.env) {
|
|
51720
51834
|
const file2 = skillsCredentialFilePath(env);
|
|
51721
|
-
return
|
|
51835
|
+
return join28(dirname18(file2), basename11(file2).replace(/^credentials/, "identity") + ".json");
|
|
51722
51836
|
}
|
|
51723
51837
|
function getApiUrl(action, env = process.env, options = {}) {
|
|
51724
51838
|
return requireSkillsApiOrigin(action, env, options);
|
|
@@ -51946,10 +52060,10 @@ async function readQuoteUnavailableCode(response) {
|
|
|
51946
52060
|
let timer;
|
|
51947
52061
|
let deadlineExceeded = false;
|
|
51948
52062
|
const expired = Symbol("quote body deadline");
|
|
51949
|
-
const deadline = new Promise((
|
|
52063
|
+
const deadline = new Promise((resolve17) => {
|
|
51950
52064
|
timer = setTimeout(() => {
|
|
51951
52065
|
deadlineExceeded = true;
|
|
51952
|
-
|
|
52066
|
+
resolve17(expired);
|
|
51953
52067
|
reader.cancel().catch(() => {});
|
|
51954
52068
|
}, 1500);
|
|
51955
52069
|
});
|
|
@@ -53432,12 +53546,12 @@ class RemotePrivatePublicationsClient {
|
|
|
53432
53546
|
previous = view;
|
|
53433
53547
|
if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
|
|
53434
53548
|
return view;
|
|
53435
|
-
await new Promise((
|
|
53549
|
+
await new Promise((resolve17) => {
|
|
53436
53550
|
const timer = setTimeout(done, Math.min(1000, until - Date.now()));
|
|
53437
53551
|
function done() {
|
|
53438
53552
|
clearTimeout(timer);
|
|
53439
53553
|
options.signal?.removeEventListener("abort", done);
|
|
53440
|
-
|
|
53554
|
+
resolve17();
|
|
53441
53555
|
}
|
|
53442
53556
|
options.signal?.addEventListener("abort", done, { once: true });
|
|
53443
53557
|
});
|
|
@@ -53725,10 +53839,10 @@ var init_remote_auth = __esm(() => {
|
|
|
53725
53839
|
});
|
|
53726
53840
|
|
|
53727
53841
|
// src/lib/workspace-profile.ts
|
|
53728
|
-
import { constants as constants11, closeSync as closeSync14, fstatSync as fstatSync14, lstatSync as
|
|
53842
|
+
import { constants as constants11, closeSync as closeSync14, fstatSync as fstatSync14, lstatSync as lstatSync19, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync2, openSync as openSync14, readFileSync as readFileSync18, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
53729
53843
|
function stat2(path) {
|
|
53730
53844
|
try {
|
|
53731
|
-
return
|
|
53845
|
+
return lstatSync19(path);
|
|
53732
53846
|
} catch (error61) {
|
|
53733
53847
|
if (error61.code === "ENOENT")
|
|
53734
53848
|
return null;
|
|
@@ -53957,8 +54071,8 @@ var init_recurring_customer = __esm(() => {
|
|
|
53957
54071
|
});
|
|
53958
54072
|
|
|
53959
54073
|
// src/lib/recurring-recovery.ts
|
|
53960
|
-
import { constants as constants12, closeSync as closeSync15, fsyncSync as fsyncSync4, fstatSync as fstatSync15, lstatSync as
|
|
53961
|
-
import { dirname as
|
|
54074
|
+
import { constants as constants12, closeSync as closeSync15, fsyncSync as fsyncSync4, fstatSync as fstatSync15, lstatSync as lstatSync20, mkdirSync as mkdirSync10, openSync as openSync15, readSync as readSync10, realpathSync as realpathSync7, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync9 } from "fs";
|
|
54075
|
+
import { dirname as dirname19, isAbsolute as isAbsolute15, join as join29, resolve as resolve17 } from "path";
|
|
53962
54076
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
53963
54077
|
|
|
53964
54078
|
class RecoveryOwner {
|
|
@@ -53966,33 +54080,33 @@ class RecoveryOwner {
|
|
|
53966
54080
|
parents = [];
|
|
53967
54081
|
constructor(directory) {
|
|
53968
54082
|
this.directory = directory;
|
|
53969
|
-
if (!isAbsolute15(directory) ||
|
|
54083
|
+
if (!isAbsolute15(directory) || resolve17(directory) !== directory || realpathSync7(directory) !== directory)
|
|
53970
54084
|
invalid5();
|
|
53971
|
-
for (let path = directory;; path =
|
|
53972
|
-
const stat3 =
|
|
54085
|
+
for (let path = directory;; path = dirname19(path)) {
|
|
54086
|
+
const stat3 = lstatSync20(path);
|
|
53973
54087
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
53974
54088
|
invalid5();
|
|
53975
54089
|
this.parents.push({ path, dev: stat3.dev, ino: stat3.ino });
|
|
53976
|
-
if (path ===
|
|
54090
|
+
if (path === dirname19(path))
|
|
53977
54091
|
break;
|
|
53978
54092
|
}
|
|
53979
54093
|
this.assert();
|
|
53980
54094
|
}
|
|
53981
54095
|
assert() {
|
|
53982
|
-
if (
|
|
54096
|
+
if (realpathSync7(this.directory) !== this.directory)
|
|
53983
54097
|
invalid5();
|
|
53984
54098
|
for (const prior of this.parents) {
|
|
53985
|
-
const now =
|
|
54099
|
+
const now = lstatSync20(prior.path);
|
|
53986
54100
|
if (!now.isDirectory() || now.isSymbolicLink() || now.dev !== prior.dev || now.ino !== prior.ino)
|
|
53987
54101
|
invalid5();
|
|
53988
54102
|
}
|
|
53989
|
-
const own2 =
|
|
54103
|
+
const own2 = lstatSync20(this.directory);
|
|
53990
54104
|
if ((own2.mode & 511) !== 448 || (own2.mode & 3584) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
53991
54105
|
invalid5();
|
|
53992
54106
|
}
|
|
53993
54107
|
read(name) {
|
|
53994
54108
|
this.assert();
|
|
53995
|
-
const fd = openSync15(
|
|
54109
|
+
const fd = openSync15(join29(this.directory, name), constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
53996
54110
|
try {
|
|
53997
54111
|
const before = fstatSync15(fd);
|
|
53998
54112
|
if (!before.isFile() || before.nlink !== 1 || (before.mode & 4095) !== 384 || before.size < 1 || before.size > 8192 || process.getuid && before.uid !== process.getuid())
|
|
@@ -54005,7 +54119,7 @@ class RecoveryOwner {
|
|
|
54005
54119
|
break;
|
|
54006
54120
|
size += n2;
|
|
54007
54121
|
}
|
|
54008
|
-
const after = fstatSync15(fd), path =
|
|
54122
|
+
const after = fstatSync15(fd), path = lstatSync20(join29(this.directory, name));
|
|
54009
54123
|
if (size !== before.size || after.size !== before.size || before.mtimeMs !== after.mtimeMs || before.ctimeMs !== after.ctimeMs || path.dev !== before.dev || path.ino !== before.ino || !path.isFile() || path.isSymbolicLink())
|
|
54010
54124
|
invalid5();
|
|
54011
54125
|
this.assert();
|
|
@@ -54018,7 +54132,7 @@ class RecoveryOwner {
|
|
|
54018
54132
|
this.assert();
|
|
54019
54133
|
const bytes = canonicalJson2(value, 8192) + `
|
|
54020
54134
|
`;
|
|
54021
|
-
const fd = openSync15(
|
|
54135
|
+
const fd = openSync15(join29(this.directory, name), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
|
|
54022
54136
|
try {
|
|
54023
54137
|
writeFileSync9(fd, bytes);
|
|
54024
54138
|
fsyncSync4(fd);
|
|
@@ -54045,14 +54159,14 @@ class RecoveryOwner {
|
|
|
54045
54159
|
if (this.read("state.json") !== expected)
|
|
54046
54160
|
invalid5();
|
|
54047
54161
|
this.assert();
|
|
54048
|
-
renameSync6(
|
|
54162
|
+
renameSync6(join29(this.directory, name), join29(this.directory, "state.json"));
|
|
54049
54163
|
this.sync();
|
|
54050
54164
|
}
|
|
54051
54165
|
async locked(action) {
|
|
54052
54166
|
this.assert();
|
|
54053
54167
|
let fd;
|
|
54054
54168
|
try {
|
|
54055
|
-
fd = openSync15(
|
|
54169
|
+
fd = openSync15(join29(this.directory, "operation.lock"), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
|
|
54056
54170
|
} catch {
|
|
54057
54171
|
throw new RecurringCustomerError("RECURRING_RECOVERY_BUSY", "Recovery is locked. Confirm the original process has stopped before explicitly reconciling the retained lock; no request was retried.");
|
|
54058
54172
|
}
|
|
@@ -54065,10 +54179,10 @@ class RecoveryOwner {
|
|
|
54065
54179
|
} finally {
|
|
54066
54180
|
closeSync15(fd);
|
|
54067
54181
|
this.assert();
|
|
54068
|
-
const now =
|
|
54182
|
+
const now = lstatSync20(join29(this.directory, "operation.lock"));
|
|
54069
54183
|
if (owner2.dev !== now.dev || owner2.ino !== now.ino || !now.isFile() || now.isSymbolicLink())
|
|
54070
54184
|
invalid5();
|
|
54071
|
-
unlinkSync5(
|
|
54185
|
+
unlinkSync5(join29(this.directory, "operation.lock"));
|
|
54072
54186
|
this.sync();
|
|
54073
54187
|
}
|
|
54074
54188
|
}
|
|
@@ -54101,7 +54215,7 @@ function base(customer, organizationId) {
|
|
|
54101
54215
|
};
|
|
54102
54216
|
}
|
|
54103
54217
|
function create(directory, intent) {
|
|
54104
|
-
if (!isAbsolute15(directory) ||
|
|
54218
|
+
if (!isAbsolute15(directory) || resolve17(directory) !== directory || realpathSync7(dirname19(directory)) !== dirname19(directory))
|
|
54105
54219
|
invalid5();
|
|
54106
54220
|
mkdirSync10(directory, { mode: 448 });
|
|
54107
54221
|
const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -56199,20 +56313,20 @@ var init_credential_state = __esm(() => {
|
|
|
56199
56313
|
|
|
56200
56314
|
// src/lib/run-state.ts
|
|
56201
56315
|
import { createHash as createHash19, randomBytes } from "crypto";
|
|
56202
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync19, readdirSync as
|
|
56203
|
-
import { extname, join as
|
|
56316
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync19, readdirSync as readdirSync10, statSync as statSync9, writeFileSync as writeFileSync10 } from "fs";
|
|
56317
|
+
import { extname, join as join30, relative as relative6 } from "path";
|
|
56204
56318
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
56205
56319
|
const now = new Date;
|
|
56206
56320
|
const id = createRunId(now);
|
|
56207
56321
|
const day = now.toISOString().slice(0, 10);
|
|
56208
56322
|
const skillName = normalizeSkillName(params.skill);
|
|
56209
56323
|
const root = getProjectStateDir(targetDir);
|
|
56210
|
-
const runDir =
|
|
56211
|
-
const logsDir =
|
|
56212
|
-
const exportDir =
|
|
56324
|
+
const runDir = join30(root, "runs", day, id);
|
|
56325
|
+
const logsDir = join30(runDir, "logs");
|
|
56326
|
+
const exportDir = join30(root, "exports", skillName, id);
|
|
56213
56327
|
mkdirSync11(logsDir, { recursive: true });
|
|
56214
56328
|
mkdirSync11(exportDir, { recursive: true });
|
|
56215
|
-
mkdirSync11(
|
|
56329
|
+
mkdirSync11(join30(root, "tmp"), { recursive: true });
|
|
56216
56330
|
const record10 = {
|
|
56217
56331
|
id,
|
|
56218
56332
|
skill: skillName,
|
|
@@ -56264,22 +56378,22 @@ function updateSkillRun(context2, patch) {
|
|
|
56264
56378
|
return context2.record;
|
|
56265
56379
|
}
|
|
56266
56380
|
function writeRunLogs(context2, stdout = "", stderr = "") {
|
|
56267
|
-
writeFileSync10(
|
|
56268
|
-
writeFileSync10(
|
|
56381
|
+
writeFileSync10(join30(context2.logsDir, "stdout.log"), stdout);
|
|
56382
|
+
writeFileSync10(join30(context2.logsDir, "stderr.log"), stderr);
|
|
56269
56383
|
}
|
|
56270
56384
|
function appendRunEvent(context2, event, data = {}) {
|
|
56271
56385
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
56272
56386
|
`;
|
|
56273
|
-
const path =
|
|
56387
|
+
const path = join30(context2.runDir, "events.ndjson");
|
|
56274
56388
|
const previous = existsSync14(path) ? readFileSync19(path, "utf-8") : "";
|
|
56275
56389
|
writeFileSync10(path, previous + line);
|
|
56276
56390
|
}
|
|
56277
56391
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
56278
|
-
const runsRoot =
|
|
56392
|
+
const runsRoot = join30(getProjectStateDir(targetDir), "runs");
|
|
56279
56393
|
if (!existsSync14(runsRoot))
|
|
56280
56394
|
return null;
|
|
56281
|
-
for (const day of
|
|
56282
|
-
const record10 = readRunRecord(
|
|
56395
|
+
for (const day of readdirSync10(runsRoot)) {
|
|
56396
|
+
const record10 = readRunRecord(join30(runsRoot, day, runId));
|
|
56283
56397
|
if (record10)
|
|
56284
56398
|
return record10;
|
|
56285
56399
|
}
|
|
@@ -56296,11 +56410,11 @@ function skillRunEnv(context2) {
|
|
|
56296
56410
|
};
|
|
56297
56411
|
}
|
|
56298
56412
|
function writeRunRecord(context2) {
|
|
56299
|
-
writeFileSync10(
|
|
56413
|
+
writeFileSync10(join30(context2.runDir, "run.json"), JSON.stringify(context2.record, null, 2) + `
|
|
56300
56414
|
`);
|
|
56301
56415
|
}
|
|
56302
56416
|
function writeArtifactsManifest(context2, artifacts) {
|
|
56303
|
-
writeFileSync10(
|
|
56417
|
+
writeFileSync10(join30(context2.runDir, "artifacts.json"), JSON.stringify({ runId: context2.record.id, artifacts }, null, 2) + `
|
|
56304
56418
|
`);
|
|
56305
56419
|
}
|
|
56306
56420
|
function collectRunArtifacts(context2) {
|
|
@@ -56320,7 +56434,7 @@ function collectRunArtifacts(context2) {
|
|
|
56320
56434
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
56321
56435
|
}
|
|
56322
56436
|
function readRunRecord(runDir) {
|
|
56323
|
-
const path =
|
|
56437
|
+
const path = join30(runDir, "run.json");
|
|
56324
56438
|
if (!existsSync14(path))
|
|
56325
56439
|
return null;
|
|
56326
56440
|
try {
|
|
@@ -56331,8 +56445,8 @@ function readRunRecord(runDir) {
|
|
|
56331
56445
|
}
|
|
56332
56446
|
function walkFiles(dir) {
|
|
56333
56447
|
const files = [];
|
|
56334
|
-
for (const entry of
|
|
56335
|
-
const full =
|
|
56448
|
+
for (const entry of readdirSync10(dir)) {
|
|
56449
|
+
const full = join30(dir, entry);
|
|
56336
56450
|
if (statSync9(full).isDirectory())
|
|
56337
56451
|
files.push(...walkFiles(full));
|
|
56338
56452
|
else
|
|
@@ -56344,7 +56458,7 @@ function createRunId(now) {
|
|
|
56344
56458
|
return `run_${now.getTime().toString(36)}_${randomBytes(4).toString("hex")}`;
|
|
56345
56459
|
}
|
|
56346
56460
|
function toProjectRelative(targetDir, path) {
|
|
56347
|
-
const rel =
|
|
56461
|
+
const rel = relative6(targetDir, path).split(/[\\/]/).join("/");
|
|
56348
56462
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
56349
56463
|
}
|
|
56350
56464
|
function mimeForPath(path) {
|
|
@@ -56589,7 +56703,7 @@ import { closeSync as closeSync16, fstatSync as fstatSync16, openSync as openSyn
|
|
|
56589
56703
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
56590
56704
|
import { createRequire as createRequire2 } from "module";
|
|
56591
56705
|
import { hostname as osHostname2 } from "os";
|
|
56592
|
-
import { isAbsolute as isAbsolute17, join as
|
|
56706
|
+
import { isAbsolute as isAbsolute17, join as join31 } from "path";
|
|
56593
56707
|
import { createRequire as createRequire22 } from "module";
|
|
56594
56708
|
function envToken2(name) {
|
|
56595
56709
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -56620,14 +56734,14 @@ function hasnaHomeDir2(env) {
|
|
|
56620
56734
|
if (override)
|
|
56621
56735
|
return override;
|
|
56622
56736
|
const home = homeDir2(env);
|
|
56623
|
-
return home ?
|
|
56737
|
+
return home ? join31(home, HASNA_HOME_DIR2) : null;
|
|
56624
56738
|
}
|
|
56625
56739
|
function appConfigDir2(name, env) {
|
|
56626
56740
|
const configRoot = absoluteOverride2(env, HASNA_CONFIG_HOME_ENV_KEY2);
|
|
56627
56741
|
if (configRoot)
|
|
56628
|
-
return
|
|
56742
|
+
return join31(configRoot, name);
|
|
56629
56743
|
const root = hasnaHomeDir2(env);
|
|
56630
|
-
return root ?
|
|
56744
|
+
return root ? join31(root, name, CONFIG_SUBDIR2) : null;
|
|
56631
56745
|
}
|
|
56632
56746
|
function credentialDiskSourceList2(name, env, profile = null) {
|
|
56633
56747
|
if (!SAFE_APP_SLUG2.test(name))
|
|
@@ -56636,7 +56750,7 @@ function credentialDiskSourceList2(name, env, profile = null) {
|
|
|
56636
56750
|
if (!directory2)
|
|
56637
56751
|
return [];
|
|
56638
56752
|
const file2 = profile ? `${CREDENTIALS_FILE2}-${profile}` : CREDENTIALS_FILE2;
|
|
56639
|
-
return [{ path:
|
|
56753
|
+
return [{ path: join31(directory2, file2), tier: "disk" }];
|
|
56640
56754
|
}
|
|
56641
56755
|
function credentialDiskSources2(name, env) {
|
|
56642
56756
|
return credentialDiskSourceList2(name, env, null).map((s) => s.path);
|
|
@@ -57750,7 +57864,7 @@ function createSecretsClientFromEnv(env = process.env, overrides = {}) {
|
|
|
57750
57864
|
});
|
|
57751
57865
|
return new SecretsClient({ ...clientOverrides, baseUrl, apiKey });
|
|
57752
57866
|
}
|
|
57753
|
-
var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE", CredentialResolutionError2, CredentialFileUnsafeError2, HASNA_HOME_ENV_KEY2 = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY2 = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY2 = "HASNA_STATION", HASNA_HOME_DIR2 = ".hasna", CONFIG_SUBDIR2 = "config", CREDENTIALS_FILE2 = "credentials", KEYCHAIN_SECURITY_BIN2 = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX2 = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS2 = 44, KEYCHAIN_SPAWN_TIMEOUT_MS2 = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG2, SAFE_PROFILE2, ILLEGAL_IN_HEADER_VALUE2, VAULT_POINTER_SHAPE2, CREDENTIAL_SHAPED_KEY2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", AMBIENT_ENVIRONMENT2, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN2 = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN2, DNS_LABEL_PATTERN2, ClientTransportConfigurationError2, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, defaultSleep = (ms) => new Promise((
|
|
57867
|
+
var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE", CredentialResolutionError2, CredentialFileUnsafeError2, HASNA_HOME_ENV_KEY2 = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY2 = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY2 = "HASNA_STATION", HASNA_HOME_DIR2 = ".hasna", CONFIG_SUBDIR2 = "config", CREDENTIALS_FILE2 = "credentials", KEYCHAIN_SECURITY_BIN2 = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX2 = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS2 = 44, KEYCHAIN_SPAWN_TIMEOUT_MS2 = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG2, SAFE_PROFILE2, ILLEGAL_IN_HEADER_VALUE2, VAULT_POINTER_SHAPE2, CREDENTIAL_SHAPED_KEY2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", AMBIENT_ENVIRONMENT2, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN2 = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN2, DNS_LABEL_PATTERN2, ClientTransportConfigurationError2, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, defaultSleep = (ms) => new Promise((resolve18) => setTimeout(resolve18, ms)), init_transport2, MAX_CREDENTIAL_FILE_BYTES22, INSPECT_CUSTOM22, CREDENTIAL_SEAL22, AMBIENT_ENVIRONMENT22, SECRETS_PACKAGE_SPECIFIER2, requireSecretsSdk22, IDEMPOTENT_METHODS22, AUTHORITY_OVERRIDE_HEADERS22, init_storage, PATHS_RESOLVER_APP_SLUG_RE2, SQLITE_SIDECAR_FILES, LEGACY_SERVICE_FILES, init_data_dir, SecretsTestIsolationError, TEST_ENTRYPOINT_RE, init_test_isolation, init_client, ApiError;
|
|
57754
57868
|
var init_sdk = __esm(() => {
|
|
57755
57869
|
init_transport2 = __esm2(() => {
|
|
57756
57870
|
CredentialResolutionError2 = class CredentialResolutionError3 extends Error {
|
|
@@ -57885,25 +57999,25 @@ var init_sdk = __esm(() => {
|
|
|
57885
57999
|
});
|
|
57886
58000
|
|
|
57887
58001
|
// src/lib/execution-secrets.ts
|
|
57888
|
-
import { constants as constants13, closeSync as closeSync17, fstatSync as fstatSync17, openSync as openSync17, readSync as readSync11, realpathSync as
|
|
58002
|
+
import { constants as constants13, closeSync as closeSync17, fstatSync as fstatSync17, openSync as openSync17, readSync as readSync11, realpathSync as realpathSync8 } from "fs";
|
|
57889
58003
|
import { hostname as stationHostname } from "os";
|
|
57890
58004
|
function selectedSecretBindingsTemplate(scope, names, createClient = createSecretsClientFromEnv) {
|
|
57891
58005
|
let secretsAuthority;
|
|
57892
58006
|
try {
|
|
57893
58007
|
secretsAuthority = createClient().baseUrl;
|
|
57894
58008
|
} catch {
|
|
57895
|
-
return
|
|
58009
|
+
return refuse2("LOCAL_SECRET_UNAVAILABLE", "Configure the Secrets CLI authority and authentication before preparing execution bindings.");
|
|
57896
58010
|
}
|
|
57897
58011
|
const { authority, workspaceId, profileRevision, slug: slug2, version: version2, bundleDigest } = scope.selection;
|
|
57898
58012
|
return {
|
|
57899
58013
|
schema: "hasna.skills-secret-bindings.v1",
|
|
57900
58014
|
selection: { authority, workspaceId, profileId: scope.profileId, profileRevision, slug: slug2, version: version2, bundleDigest },
|
|
57901
|
-
consumer: { stationId: process.env.HASNA_STATION || stationHostname(), workspaceDirectory:
|
|
58015
|
+
consumer: { stationId: process.env.HASNA_STATION || stationHostname(), workspaceDirectory: realpathSync8(scope.cwd) },
|
|
57902
58016
|
secretsAuthority,
|
|
57903
58017
|
bindings: Object.fromEntries(names.map((name) => [name, ""]))
|
|
57904
58018
|
};
|
|
57905
58019
|
}
|
|
57906
|
-
function
|
|
58020
|
+
function refuse2(code2, message) {
|
|
57907
58021
|
throw new SkillSelectionError(code2, message);
|
|
57908
58022
|
}
|
|
57909
58023
|
function record10(value) {
|
|
@@ -57912,48 +58026,48 @@ function record10(value) {
|
|
|
57912
58026
|
function exactKeys2(value, keys) {
|
|
57913
58027
|
return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
57914
58028
|
}
|
|
57915
|
-
function
|
|
58029
|
+
function identifier3(value) {
|
|
57916
58030
|
return typeof value === "string" && value.length > 0 && value.length <= 2048 && !/[\x00-\x20\x7f]/.test(value);
|
|
57917
58031
|
}
|
|
57918
58032
|
function declaredSecretNames(value) {
|
|
57919
58033
|
if (value === undefined)
|
|
57920
58034
|
return [];
|
|
57921
58035
|
if (!Array.isArray(value) || value.length > 32 || value.some((name) => typeof name !== "string" || !/^[A-Z][A-Z0-9_]{0,127}$/.test(name)) || new Set(value).size !== value.length) {
|
|
57922
|
-
return
|
|
58036
|
+
return refuse2("INVALID_SKILL_MANIFEST", "Runtime environment references must be unique uppercase identifiers (at most 32).");
|
|
57923
58037
|
}
|
|
57924
58038
|
if (value.some((name) => /^(?:PATH|HOME|TMPDIR|TEMP|TMP|LANG|LC_ALL|TERM|SHELL|ENV|BASH_ENV|IFS|NODE_OPTIONS|NODE_PATH)$/.test(name) || /^(?:SKILLS_|BUN_|PYTHON|LD_|DYLD_)/.test(name))) {
|
|
57925
|
-
return
|
|
58039
|
+
return refuse2("INVALID_SKILL_MANIFEST", "Runtime environment references cannot override execution controls.");
|
|
57926
58040
|
}
|
|
57927
58041
|
return value;
|
|
57928
58042
|
}
|
|
57929
58043
|
function validateSelectedSecretBindings(value, scope, names) {
|
|
57930
58044
|
if (!record10(value) || !exactKeys2(value, ["schema", "selection", "consumer", "secretsAuthority", "bindings"]) || value.schema !== "hasna.skills-secret-bindings.v1" || !record10(value.selection) || !exactKeys2(value.selection, ["authority", "workspaceId", "profileId", "profileRevision", "slug", "version", "bundleDigest"]) || !record10(value.consumer) || !exactKeys2(value.consumer, ["stationId", "workspaceDirectory"]) || !record10(value.bindings)) {
|
|
57931
|
-
return
|
|
58045
|
+
return refuse2("INVALID_SECRET_BINDINGS", "Secret bindings do not match the hasna.skills-secret-bindings.v1 contract.");
|
|
57932
58046
|
}
|
|
57933
58047
|
for (const [key, expected] of Object.entries({ authority: scope.selection.authority, workspaceId: scope.selection.workspaceId, profileId: scope.profileId, profileRevision: scope.selection.profileRevision, slug: scope.selection.slug, version: scope.selection.version, bundleDigest: scope.selection.bundleDigest })) {
|
|
57934
58048
|
if (value.selection[key] !== expected)
|
|
57935
|
-
return
|
|
58049
|
+
return refuse2("SECRET_BINDING_SCOPE_MISMATCH", "Secret bindings do not match the exact selected authority, workspace, profile, revision, version and digest.");
|
|
57936
58050
|
}
|
|
57937
58051
|
let workspaceDirectory;
|
|
57938
58052
|
try {
|
|
57939
|
-
workspaceDirectory =
|
|
58053
|
+
workspaceDirectory = realpathSync8(scope.cwd);
|
|
57940
58054
|
} catch {
|
|
57941
|
-
return
|
|
58055
|
+
return refuse2("SECRET_BINDING_CONSUMER_MISMATCH", "The execution workspace cannot be resolved.");
|
|
57942
58056
|
}
|
|
57943
58057
|
if (value.consumer.stationId !== (process.env.HASNA_STATION || stationHostname()) || value.consumer.workspaceDirectory !== workspaceDirectory) {
|
|
57944
|
-
return
|
|
58058
|
+
return refuse2("SECRET_BINDING_CONSUMER_MISMATCH", "Secret bindings do not match this station and canonical workspace directory.");
|
|
57945
58059
|
}
|
|
57946
58060
|
try {
|
|
57947
|
-
if (!
|
|
58061
|
+
if (!identifier3(value.secretsAuthority))
|
|
57948
58062
|
throw new Error;
|
|
57949
58063
|
const url2 = new URL(value.secretsAuthority);
|
|
57950
58064
|
if (url2.protocol !== "https:" && !(url2.protocol === "http:" && ["127.0.0.1", "[::1]", "localhost"].includes(url2.hostname)) || url2.username || url2.password || url2.search || url2.hash || !url2.pathname.endsWith("/v1") || url2.href !== value.secretsAuthority)
|
|
57951
58065
|
throw new Error;
|
|
57952
58066
|
} catch {
|
|
57953
|
-
return
|
|
58067
|
+
return refuse2("INVALID_SECRET_BINDINGS", "Secret bindings require a canonical HTTPS Secrets /v1 authority (loopback HTTP is allowed).");
|
|
57954
58068
|
}
|
|
57955
|
-
if (!exactKeys2(value.bindings, names) || Object.values(value.bindings).some((key) => !
|
|
57956
|
-
return
|
|
58069
|
+
if (!exactKeys2(value.bindings, names) || Object.values(value.bindings).some((key) => !identifier3(key) || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(key) || key.split("/").some((part) => !part || part === "." || part === ".."))) {
|
|
58070
|
+
return refuse2("INVALID_SECRET_BINDINGS", "Bind every declared environment name exactly once to a vault key; undeclared bindings and values are refused.");
|
|
57957
58071
|
}
|
|
57958
58072
|
return structuredClone(value);
|
|
57959
58073
|
}
|
|
@@ -57964,10 +58078,10 @@ async function resolveSelectedSecrets(bindings, createClient = createSecretsClie
|
|
|
57964
58078
|
try {
|
|
57965
58079
|
client = createClient();
|
|
57966
58080
|
} catch {
|
|
57967
|
-
return
|
|
58081
|
+
return refuse2("LOCAL_SECRET_UNAVAILABLE", "The configured Secrets client could not authenticate. No ambient credential fallback was attempted.");
|
|
57968
58082
|
}
|
|
57969
58083
|
if (client.baseUrl !== bindings.secretsAuthority)
|
|
57970
|
-
return
|
|
58084
|
+
return refuse2("SECRET_BINDING_AUTHORITY_MISMATCH", "The configured Secrets authority differs from the reviewed binding. No secret was requested.");
|
|
57971
58085
|
const env = {};
|
|
57972
58086
|
const signal = AbortSignal.timeout(15000);
|
|
57973
58087
|
try {
|
|
@@ -57979,7 +58093,7 @@ async function resolveSelectedSecrets(bindings, createClient = createSecretsClie
|
|
|
57979
58093
|
}
|
|
57980
58094
|
return env;
|
|
57981
58095
|
} catch {
|
|
57982
|
-
return
|
|
58096
|
+
return refuse2("LOCAL_SECRET_UNAVAILABLE", "A declared secret could not be resolved, was invalid, or has expired. The skill was not started; no fallback was attempted.");
|
|
57983
58097
|
}
|
|
57984
58098
|
}
|
|
57985
58099
|
function redactExecutionSecrets(text3, env) {
|
|
@@ -58129,8 +58243,8 @@ __export(exports_selected_run, {
|
|
|
58129
58243
|
});
|
|
58130
58244
|
import { createHash as createHash20 } from "crypto";
|
|
58131
58245
|
import { spawn } from "child_process";
|
|
58132
|
-
import { mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync11, realpathSync as
|
|
58133
|
-
import { dirname as
|
|
58246
|
+
import { mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync11, realpathSync as realpathSync9 } from "fs";
|
|
58247
|
+
import { dirname as dirname20, join as join32, resolve as resolve18 } from "path";
|
|
58134
58248
|
import { tmpdir, hostname as stationHostname2 } from "os";
|
|
58135
58249
|
async function resolveSelectedRun(spec, profileId, options = {}) {
|
|
58136
58250
|
const context2 = await resolveSelectionContext(profileId, options);
|
|
@@ -58210,7 +58324,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
58210
58324
|
throw new SkillSelectionError("INVALID_SECRET_BINDINGS", "Explicit environment values must be bounded strings without NUL bytes.");
|
|
58211
58325
|
secretEnv[name] = value;
|
|
58212
58326
|
}
|
|
58213
|
-
const runDirectory = mkdtempSync3(
|
|
58327
|
+
const runDirectory = mkdtempSync3(join32(tmpdir(), "skills-execution-"));
|
|
58214
58328
|
const paths = new SkillEntryPaths;
|
|
58215
58329
|
for (const entry of entries) {
|
|
58216
58330
|
paths.add(entry.path, 100, () => {
|
|
@@ -58218,12 +58332,12 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
58218
58332
|
}, () => {
|
|
58219
58333
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
58220
58334
|
});
|
|
58221
|
-
const destination =
|
|
58222
|
-
mkdirSync12(
|
|
58335
|
+
const destination = join32(runDirectory, entry.path);
|
|
58336
|
+
mkdirSync12(dirname20(destination), { recursive: true, mode: 448 });
|
|
58223
58337
|
writeFileSync11(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
58224
58338
|
}
|
|
58225
58339
|
env.SKILLS_INPUT_JSON = input2;
|
|
58226
|
-
env.SKILLS_WORKSPACE_DIR =
|
|
58340
|
+
env.SKILLS_WORKSPACE_DIR = resolve18(options.cwd ?? process.cwd());
|
|
58227
58341
|
env.SKILLS_RUN_DIR = runDirectory;
|
|
58228
58342
|
if (runtime.version) {
|
|
58229
58343
|
const version2 = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], "--version"], runDirectory, env, "", Math.min(timeoutMs, 5000));
|
|
@@ -58236,7 +58350,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
58236
58350
|
const { authority: authority2, workspaceId, profileRevision, slug: slug2, version: version2, bundleDigest } = selection2;
|
|
58237
58351
|
const request2 = {
|
|
58238
58352
|
selection: { authority: authority2, workspaceId, profileId, profileRevision, slug: slug2, version: version2, bundleDigest },
|
|
58239
|
-
consumer: { stationId: process.env.HASNA_STATION || stationHostname2(), workspaceDirectory:
|
|
58353
|
+
consumer: { stationId: process.env.HASNA_STATION || stationHostname2(), workspaceDirectory: realpathSync9(options.cwd ?? process.cwd()) }
|
|
58240
58354
|
};
|
|
58241
58355
|
const grant = await (options.resolveExecutionGrant ?? resolveExecutionGrant)(request2);
|
|
58242
58356
|
if (!grant || !grantIdentifier(grant.policyRevision) || !grantIdentifier(grant.grantId))
|
|
@@ -58246,7 +58360,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
58246
58360
|
}
|
|
58247
58361
|
if (bindings)
|
|
58248
58362
|
secretEnv = await resolveSelectedSecrets(bindings, options.createSecretsClient);
|
|
58249
|
-
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [],
|
|
58363
|
+
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], join32(runDirectory, declaredEntry), ...args], runDirectory, { ...env, ...secretEnv }, input2, timeoutMs);
|
|
58250
58364
|
result.stdout = redactExecutionSecrets(result.stdout, secretEnv);
|
|
58251
58365
|
result.stderr = redactExecutionSecrets(result.stderr, secretEnv);
|
|
58252
58366
|
const receipt = {
|
|
@@ -58259,7 +58373,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
58259
58373
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
58260
58374
|
...result
|
|
58261
58375
|
};
|
|
58262
|
-
writeFileSync11(
|
|
58376
|
+
writeFileSync11(join32(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
|
|
58263
58377
|
return receipt;
|
|
58264
58378
|
}
|
|
58265
58379
|
async function subprocess(command, cwd, env, input2, timeoutMs) {
|
|
@@ -58448,8 +58562,8 @@ var init_blog_article = __esm(() => {
|
|
|
58448
58562
|
});
|
|
58449
58563
|
|
|
58450
58564
|
// src/mcp/operation-tools.ts
|
|
58451
|
-
import { existsSync as existsSync15, readdirSync as
|
|
58452
|
-
import { join as
|
|
58565
|
+
import { existsSync as existsSync15, readdirSync as readdirSync11, statSync as statSync10 } from "fs";
|
|
58566
|
+
import { join as join33 } from "path";
|
|
58453
58567
|
function registerOperationTools(server) {
|
|
58454
58568
|
server.registerTool("cloud_skill_eligibility", {
|
|
58455
58569
|
title: "Cloud Skill Eligibility",
|
|
@@ -58925,8 +59039,8 @@ function registerOperationTools(server) {
|
|
|
58925
59039
|
let skillCount = 0;
|
|
58926
59040
|
if (exists) {
|
|
58927
59041
|
try {
|
|
58928
|
-
skillCount =
|
|
58929
|
-
const full =
|
|
59042
|
+
skillCount = readdirSync11(agentSkillsPath).filter((f) => {
|
|
59043
|
+
const full = join33(agentSkillsPath, f);
|
|
58930
59044
|
return !f.startsWith(".") && statSync10(full).isDirectory();
|
|
58931
59045
|
}).length;
|
|
58932
59046
|
} catch {}
|
|
@@ -58994,14 +59108,14 @@ var init_operation_tools = __esm(() => {
|
|
|
58994
59108
|
|
|
58995
59109
|
// src/lib/feedback.ts
|
|
58996
59110
|
import { appendFileSync, existsSync as existsSync16, mkdirSync as mkdirSync13 } from "fs";
|
|
58997
|
-
import { dirname as
|
|
59111
|
+
import { dirname as dirname21, join as join34 } from "path";
|
|
58998
59112
|
import { Database } from "bun:sqlite";
|
|
58999
59113
|
function getFeedbackDbPath() {
|
|
59000
|
-
return
|
|
59114
|
+
return join34(getDataDir(), "skills.db");
|
|
59001
59115
|
}
|
|
59002
59116
|
function getFeedbackDb() {
|
|
59003
59117
|
const dbPath = getFeedbackDbPath();
|
|
59004
|
-
const dir =
|
|
59118
|
+
const dir = dirname21(dbPath);
|
|
59005
59119
|
if (!existsSync16(dir))
|
|
59006
59120
|
mkdirSync13(dir, { recursive: true });
|
|
59007
59121
|
const db = new Database(dbPath);
|
|
@@ -59029,8 +59143,8 @@ function saveFeedback(input2) {
|
|
|
59029
59143
|
throw new Error("Feedback message is required");
|
|
59030
59144
|
const category = input2.category ?? "general";
|
|
59031
59145
|
if (isApiMode()) {
|
|
59032
|
-
const path =
|
|
59033
|
-
const dir =
|
|
59146
|
+
const path = join34(getDataDir(), "feedback.jsonl");
|
|
59147
|
+
const dir = dirname21(path);
|
|
59034
59148
|
if (!existsSync16(dir))
|
|
59035
59149
|
mkdirSync13(dir, { recursive: true });
|
|
59036
59150
|
appendFileSync(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
|
|
@@ -59194,9 +59308,9 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
59194
59308
|
|
|
59195
59309
|
// src/lib/scheduler.ts
|
|
59196
59310
|
import { existsSync as existsSync17, readFileSync as readFileSync21, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "fs";
|
|
59197
|
-
import { join as
|
|
59311
|
+
import { join as join35 } from "path";
|
|
59198
59312
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
59199
|
-
return
|
|
59313
|
+
return join35(targetDir, ".skills", "schedules.json");
|
|
59200
59314
|
}
|
|
59201
59315
|
function loadSchedules(targetDir = process.cwd()) {
|
|
59202
59316
|
const path = getSchedulesPath(targetDir);
|
|
@@ -59209,7 +59323,7 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
59209
59323
|
}
|
|
59210
59324
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
59211
59325
|
const path = getSchedulesPath(targetDir);
|
|
59212
|
-
const dir =
|
|
59326
|
+
const dir = join35(targetDir, ".skills");
|
|
59213
59327
|
if (!existsSync17(dir))
|
|
59214
59328
|
mkdirSync14(dir, { recursive: true });
|
|
59215
59329
|
writeFileSync12(path, JSON.stringify(data, null, 2));
|
|
@@ -59486,11 +59600,11 @@ import {
|
|
|
59486
59600
|
existsSync as existsSync18,
|
|
59487
59601
|
mkdirSync as mkdirSync15,
|
|
59488
59602
|
readFileSync as readFileSync22,
|
|
59489
|
-
readdirSync as
|
|
59603
|
+
readdirSync as readdirSync12,
|
|
59490
59604
|
statSync as statSync11,
|
|
59491
59605
|
writeFileSync as writeFileSync13
|
|
59492
59606
|
} from "fs";
|
|
59493
|
-
import { dirname as
|
|
59607
|
+
import { dirname as dirname22, join as join36, normalize as normalize4, relative as relative7, sep as sep8 } from "path";
|
|
59494
59608
|
function resolveSkillsNativeStorageConfig(env = process.env) {
|
|
59495
59609
|
assertNoRetiredModeEnvVars(env, {
|
|
59496
59610
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -59531,7 +59645,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
59531
59645
|
local: {
|
|
59532
59646
|
dataDir: getDataDir(),
|
|
59533
59647
|
projectStateDir: getProjectStateDir(targetDir),
|
|
59534
|
-
feedbackDbPath:
|
|
59648
|
+
feedbackDbPath: join36(getDataDir(), "skills.db")
|
|
59535
59649
|
},
|
|
59536
59650
|
remote: {
|
|
59537
59651
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -59554,7 +59668,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
59554
59668
|
if (existsSync18(projectStateDir)) {
|
|
59555
59669
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
59556
59670
|
const bytes = readFileSync22(filePath);
|
|
59557
|
-
const relativePath = toPosix(
|
|
59671
|
+
const relativePath = toPosix(relative7(targetDir, filePath));
|
|
59558
59672
|
files.push({
|
|
59559
59673
|
path: relativePath,
|
|
59560
59674
|
sizeBytes: bytes.byteLength,
|
|
@@ -59611,8 +59725,8 @@ function parsePositiveInteger(value) {
|
|
|
59611
59725
|
}
|
|
59612
59726
|
function walkFiles2(dir) {
|
|
59613
59727
|
const files = [];
|
|
59614
|
-
for (const entry of
|
|
59615
|
-
const full =
|
|
59728
|
+
for (const entry of readdirSync12(dir)) {
|
|
59729
|
+
const full = join36(dir, entry);
|
|
59616
59730
|
const stats = statSync11(full);
|
|
59617
59731
|
if (stats.isDirectory())
|
|
59618
59732
|
files.push(...walkFiles2(full));
|
|
@@ -59850,20 +59964,20 @@ var init_private_publication_customer = __esm(() => {
|
|
|
59850
59964
|
});
|
|
59851
59965
|
|
|
59852
59966
|
// src/lib/private-publication-recovery.ts
|
|
59853
|
-
import { constants as constants14, closeSync as closeSync18, fsyncSync as fsyncSync5, fstatSync as fstatSync18, lstatSync as
|
|
59854
|
-
import { dirname as
|
|
59967
|
+
import { constants as constants14, closeSync as closeSync18, fsyncSync as fsyncSync5, fstatSync as fstatSync18, lstatSync as lstatSync21, mkdirSync as mkdirSync16, openSync as openSync18, readSync as readSync12, realpathSync as realpathSync10, renameSync as renameSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
|
|
59968
|
+
import { dirname as dirname23, isAbsolute as isAbsolute18, join as join37, resolve as resolve19 } from "path";
|
|
59855
59969
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
59856
59970
|
function safeDirectory(directory2) {
|
|
59857
|
-
if (!isAbsolute18(directory2) || directory2 !==
|
|
59971
|
+
if (!isAbsolute18(directory2) || directory2 !== resolve19(directory2) || realpathSync10(directory2) !== directory2)
|
|
59858
59972
|
return fail2();
|
|
59859
|
-
for (let path = directory2;; path =
|
|
59860
|
-
const stat3 =
|
|
59973
|
+
for (let path = directory2;; path = dirname23(path)) {
|
|
59974
|
+
const stat3 = lstatSync21(path);
|
|
59861
59975
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
59862
59976
|
return fail2();
|
|
59863
|
-
if (path ===
|
|
59977
|
+
if (path === dirname23(path))
|
|
59864
59978
|
break;
|
|
59865
59979
|
}
|
|
59866
|
-
const own2 =
|
|
59980
|
+
const own2 = lstatSync21(directory2);
|
|
59867
59981
|
if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
59868
59982
|
return fail2();
|
|
59869
59983
|
return { dev: own2.dev, ino: own2.ino };
|
|
@@ -59874,7 +59988,7 @@ function unchangedDirectory(directory2, identity3) {
|
|
|
59874
59988
|
return fail2();
|
|
59875
59989
|
}
|
|
59876
59990
|
function readOwned(directory2, name, max) {
|
|
59877
|
-
const identity3 = safeDirectory(directory2), file2 =
|
|
59991
|
+
const identity3 = safeDirectory(directory2), file2 = join37(directory2, name);
|
|
59878
59992
|
const fd = openSync18(file2, constants14.O_RDONLY | constants14.O_NOFOLLOW);
|
|
59879
59993
|
try {
|
|
59880
59994
|
const stat3 = fstatSync18(fd);
|
|
@@ -59898,7 +60012,7 @@ function readOwned(directory2, name, max) {
|
|
|
59898
60012
|
}
|
|
59899
60013
|
}
|
|
59900
60014
|
function writeOwned(directory2, name, bytes) {
|
|
59901
|
-
const fd = openSync18(
|
|
60015
|
+
const fd = openSync18(join37(directory2, name), constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
|
|
59902
60016
|
try {
|
|
59903
60017
|
writeFileSync14(fd, bytes);
|
|
59904
60018
|
fsyncSync5(fd);
|
|
@@ -59911,7 +60025,7 @@ function save(directory2, value) {
|
|
|
59911
60025
|
writeOwned(directory2, temporary, JSON.stringify(value) + `
|
|
59912
60026
|
`);
|
|
59913
60027
|
unchangedDirectory(directory2, identity3);
|
|
59914
|
-
renameSync7(
|
|
60028
|
+
renameSync7(join37(directory2, temporary), join37(directory2, "receipt.json"));
|
|
59915
60029
|
const fd = openSync18(directory2, constants14.O_RDONLY | constants14.O_NOFOLLOW);
|
|
59916
60030
|
try {
|
|
59917
60031
|
fsyncSync5(fd);
|
|
@@ -59924,7 +60038,7 @@ function bind(client, receipt) {
|
|
|
59924
60038
|
throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
|
|
59925
60039
|
}
|
|
59926
60040
|
async function locked(directory2, action) {
|
|
59927
|
-
const identity3 = safeDirectory(directory2), file2 =
|
|
60041
|
+
const identity3 = safeDirectory(directory2), file2 = join37(directory2, "operation.lock");
|
|
59928
60042
|
let fd;
|
|
59929
60043
|
try {
|
|
59930
60044
|
fd = openSync18(file2, constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
|
|
@@ -59940,7 +60054,7 @@ async function locked(directory2, action) {
|
|
|
59940
60054
|
} finally {
|
|
59941
60055
|
closeSync18(fd);
|
|
59942
60056
|
unchangedDirectory(directory2, identity3);
|
|
59943
|
-
const now =
|
|
60057
|
+
const now = lstatSync21(file2);
|
|
59944
60058
|
if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
|
|
59945
60059
|
fail2();
|
|
59946
60060
|
unlinkSync6(file2);
|
|
@@ -59992,11 +60106,11 @@ async function preparePrivatePublication(client, sourceDirectory, recoveryDirect
|
|
|
59992
60106
|
phase: "prepared",
|
|
59993
60107
|
intent: null
|
|
59994
60108
|
};
|
|
59995
|
-
if (!isAbsolute18(recoveryDirectory) ||
|
|
60109
|
+
if (!isAbsolute18(recoveryDirectory) || resolve19(recoveryDirectory) !== recoveryDirectory || realpathSync10(dirname23(recoveryDirectory)) !== dirname23(recoveryDirectory))
|
|
59996
60110
|
return fail2();
|
|
59997
60111
|
mkdirSync16(recoveryDirectory, { mode: 448 });
|
|
59998
60112
|
safeDirectory(recoveryDirectory);
|
|
59999
|
-
const parent = openSync18(
|
|
60113
|
+
const parent = openSync18(dirname23(recoveryDirectory), constants14.O_RDONLY | constants14.O_NOFOLLOW);
|
|
60000
60114
|
try {
|
|
60001
60115
|
fsyncSync5(parent);
|
|
60002
60116
|
} finally {
|
|
@@ -60808,7 +60922,7 @@ var RequestError, nonJoinedHeaders, validHeaderName, isHttpWhitespace = (code2)
|
|
|
60808
60922
|
request2[bodyBufferKey] = buffered;
|
|
60809
60923
|
return Promise.resolve(buffered);
|
|
60810
60924
|
}
|
|
60811
|
-
const promise3 = new Promise((
|
|
60925
|
+
const promise3 = new Promise((resolve20, reject) => {
|
|
60812
60926
|
const chunks = [];
|
|
60813
60927
|
let settled = false;
|
|
60814
60928
|
const finish = (callback) => {
|
|
@@ -60830,7 +60944,7 @@ var RequestError, nonJoinedHeaders, validHeaderName, isHttpWhitespace = (code2)
|
|
|
60830
60944
|
reject(error61 ?? normalizeAbortError(request2, incoming));
|
|
60831
60945
|
else {
|
|
60832
60946
|
request2[bodyBufferKey] = recovered;
|
|
60833
|
-
|
|
60947
|
+
resolve20(recovered);
|
|
60834
60948
|
}
|
|
60835
60949
|
});
|
|
60836
60950
|
return true;
|
|
@@ -60842,7 +60956,7 @@ var RequestError, nonJoinedHeaders, validHeaderName, isHttpWhitespace = (code2)
|
|
|
60842
60956
|
finish(() => {
|
|
60843
60957
|
const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks);
|
|
60844
60958
|
request2[bodyBufferKey] = buffer;
|
|
60845
|
-
|
|
60959
|
+
resolve20(buffer);
|
|
60846
60960
|
});
|
|
60847
60961
|
};
|
|
60848
60962
|
const onError = (error61) => {
|
|
@@ -61116,7 +61230,7 @@ var RequestError, nonJoinedHeaders, validHeaderName, isHttpWhitespace = (code2)
|
|
|
61116
61230
|
});
|
|
61117
61231
|
if (!chunk) {
|
|
61118
61232
|
if (i === 1) {
|
|
61119
|
-
await new Promise((
|
|
61233
|
+
await new Promise((resolve20) => setTimeout(resolve20));
|
|
61120
61234
|
maxReadCount = 3;
|
|
61121
61235
|
continue;
|
|
61122
61236
|
}
|
|
@@ -62346,9 +62460,9 @@ data:
|
|
|
62346
62460
|
const initRequest = messages.find((m) => isInitializeRequest(m));
|
|
62347
62461
|
const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
|
|
62348
62462
|
if (this._enableJsonResponse) {
|
|
62349
|
-
return new Promise((
|
|
62463
|
+
return new Promise((resolve20) => {
|
|
62350
62464
|
this._streamMapping.set(streamId, {
|
|
62351
|
-
resolveJson:
|
|
62465
|
+
resolveJson: resolve20,
|
|
62352
62466
|
cleanup: () => {
|
|
62353
62467
|
this._streamMapping.delete(streamId);
|
|
62354
62468
|
}
|
|
@@ -62717,19 +62831,19 @@ async function connectMcpForNode() {
|
|
|
62717
62831
|
return { server: server2, transport };
|
|
62718
62832
|
}
|
|
62719
62833
|
function readBody(req) {
|
|
62720
|
-
return new Promise((
|
|
62834
|
+
return new Promise((resolve20, reject) => {
|
|
62721
62835
|
const chunks = [];
|
|
62722
62836
|
req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
62723
62837
|
req.on("end", () => {
|
|
62724
62838
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
62725
62839
|
if (!raw.trim()) {
|
|
62726
|
-
|
|
62840
|
+
resolve20(undefined);
|
|
62727
62841
|
return;
|
|
62728
62842
|
}
|
|
62729
62843
|
try {
|
|
62730
|
-
|
|
62844
|
+
resolve20(JSON.parse(raw));
|
|
62731
62845
|
} catch {
|
|
62732
|
-
|
|
62846
|
+
resolve20(undefined);
|
|
62733
62847
|
}
|
|
62734
62848
|
});
|
|
62735
62849
|
req.on("error", reject);
|
|
@@ -62771,9 +62885,9 @@ async function startSkillsMcpHttpServer(options = {}) {
|
|
|
62771
62885
|
}
|
|
62772
62886
|
}
|
|
62773
62887
|
});
|
|
62774
|
-
await new Promise((
|
|
62888
|
+
await new Promise((resolve20, reject) => {
|
|
62775
62889
|
httpServer.once("error", reject);
|
|
62776
|
-
httpServer.listen(port, hostname4, () =>
|
|
62890
|
+
httpServer.listen(port, hostname4, () => resolve20());
|
|
62777
62891
|
});
|
|
62778
62892
|
const address = httpServer.address();
|
|
62779
62893
|
const listenPort = typeof address === "object" && address ? address.port : port;
|