@hasna/skills 0.10.28 → 0.10.30
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 +37 -0
- package/bin/index.js +1123 -920
- package/bin/mcp.js +357 -278
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +658 -470
- package/dist/lib/agent-adapters.d.ts +7 -1
- package/dist/lib/agent-sumi.d.ts +15 -0
- package/dist/lib/native-discovery-roots.d.ts +1 -1
- package/dist/lib/registry.d.ts +20 -3
- package/dist/lib/selection-resolver.d.ts +1 -0
- package/dist/lib/skill-context.d.ts +2 -0
- package/dist/sdk/index.js +650 -466
- 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.30",
|
|
20023
20023
|
description: "Skills library for AI coding agents",
|
|
20024
20024
|
type: "module",
|
|
20025
20025
|
bin: {
|
|
@@ -38184,6 +38184,8 @@ var init_native_discovery_roots = __esm(() => {
|
|
|
38184
38184
|
["codex", ".codex/skills"],
|
|
38185
38185
|
["codex", ".agents/skills"],
|
|
38186
38186
|
["gemini", ".gemini/skills"],
|
|
38187
|
+
["sumi", ".sumi/skills"],
|
|
38188
|
+
["sumi", ".sumi/skill"],
|
|
38187
38189
|
["codewith", ".codewith/skills"],
|
|
38188
38190
|
["opencode", ".config/opencode/skills"],
|
|
38189
38191
|
["opencode", ".opencode/skills"],
|
|
@@ -38201,7 +38203,7 @@ var init_native_discovery_roots = __esm(() => {
|
|
|
38201
38203
|
// src/lib/agent-adapters.ts
|
|
38202
38204
|
var INTEGRATION_AGENTS;
|
|
38203
38205
|
var init_agent_adapters = __esm(() => {
|
|
38204
|
-
INTEGRATION_AGENTS = ["claude", "codex", "gemini", "opencode", "cursor", "hermes"];
|
|
38206
|
+
INTEGRATION_AGENTS = ["claude", "codex", "gemini", "opencode", "cursor", "hermes", "sumi"];
|
|
38205
38207
|
});
|
|
38206
38208
|
|
|
38207
38209
|
// src/lib/agent-policy-limits.ts
|
|
@@ -48092,6 +48094,38 @@ var init_agent_bridge = __esm(() => {
|
|
|
48092
48094
|
// src/lib/agent-codex.ts
|
|
48093
48095
|
var init_agent_codex = () => {};
|
|
48094
48096
|
|
|
48097
|
+
// src/lib/agent-sumi.ts
|
|
48098
|
+
import { existsSync as existsSync8, lstatSync as lstatSync13, realpathSync as realpathSync4 } from "fs";
|
|
48099
|
+
import { join as join18, resolve as resolve10 } from "path";
|
|
48100
|
+
function sumiConfigDirectory(home, env = process.env) {
|
|
48101
|
+
for (const key of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
|
|
48102
|
+
if (env[key] !== undefined)
|
|
48103
|
+
throw new Error(`Sumi ${key} requires a dedicated discovery adapter; unset it before Skills integration`);
|
|
48104
|
+
const selected = (key) => env[key]?.trim() ? env[key] : undefined;
|
|
48105
|
+
const expand = (value) => resolve10(value === "~" ? home : value.startsWith("~/") ? join18(home, value.slice(2)) : value);
|
|
48106
|
+
const explicit = selected("SUMI_CONFIG_DIR");
|
|
48107
|
+
const xdg = selected("XDG_CONFIG_HOME");
|
|
48108
|
+
const custom2 = selected("SUMI_HOME");
|
|
48109
|
+
const canonical5 = explicit ? expand(explicit) : xdg ? join18(expand(xdg), "sumi") : join18(custom2 ? expand(custom2) : join18(home, ".hasna-internal/sumi"), "config");
|
|
48110
|
+
if (explicit || xdg || custom2)
|
|
48111
|
+
return canonical5;
|
|
48112
|
+
const legacy = join18(home, ".config/sumi");
|
|
48113
|
+
const a = lstatSync13(canonical5, { throwIfNoEntry: false }), b = lstatSync13(legacy, { throwIfNoEntry: false });
|
|
48114
|
+
if (a && b && realpathSync4(canonical5) !== realpathSync4(legacy))
|
|
48115
|
+
throw new Error("Sumi config roots conflict; complete native home adoption before Skills integration");
|
|
48116
|
+
const path = a ? canonical5 : b ? legacy : canonical5;
|
|
48117
|
+
if (!existsSync8(path))
|
|
48118
|
+
return path;
|
|
48119
|
+
const physical = realpathSync4(path);
|
|
48120
|
+
if ((a?.isSymbolicLink() || b?.isSymbolicLink()) && ![canonical5, legacy].includes(physical))
|
|
48121
|
+
throw new Error("Sumi config alias must resolve to its canonical or legacy root");
|
|
48122
|
+
return physical;
|
|
48123
|
+
}
|
|
48124
|
+
function sumiConfigPath(home) {
|
|
48125
|
+
return join18(sumiConfigDirectory(home), "sumi.json");
|
|
48126
|
+
}
|
|
48127
|
+
var init_agent_sumi = () => {};
|
|
48128
|
+
|
|
48095
48129
|
// src/lib/agent-integration.ts
|
|
48096
48130
|
var init_agent_integration = __esm(() => {
|
|
48097
48131
|
init_codex_plugin_skill_controls();
|
|
@@ -48105,6 +48139,7 @@ var init_agent_integration = __esm(() => {
|
|
|
48105
48139
|
init_agent_discovery();
|
|
48106
48140
|
init_agent_adapters();
|
|
48107
48141
|
init_agent_codex();
|
|
48142
|
+
init_agent_sumi();
|
|
48108
48143
|
init_agent_hermes();
|
|
48109
48144
|
init_claude_settings_witness();
|
|
48110
48145
|
});
|
|
@@ -48142,17 +48177,17 @@ var init_skill_aliases = __esm(() => {
|
|
|
48142
48177
|
});
|
|
48143
48178
|
|
|
48144
48179
|
// src/lib/project-state.ts
|
|
48145
|
-
import { existsSync as
|
|
48146
|
-
import { join as
|
|
48180
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
|
|
48181
|
+
import { join as join19 } from "path";
|
|
48147
48182
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
48148
|
-
return
|
|
48183
|
+
return join19(targetDir, SKILLS_PROJECT_DIR);
|
|
48149
48184
|
}
|
|
48150
48185
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
48151
|
-
return
|
|
48186
|
+
return join19(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
48152
48187
|
}
|
|
48153
48188
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
48154
48189
|
const path = getProjectConfigPath(targetDir);
|
|
48155
|
-
if (!
|
|
48190
|
+
if (!existsSync9(path))
|
|
48156
48191
|
return null;
|
|
48157
48192
|
try {
|
|
48158
48193
|
return normalizeProjectConfig(JSON.parse(readFileSync12(path, "utf-8")));
|
|
@@ -48263,8 +48298,8 @@ var init_project_state = __esm(() => {
|
|
|
48263
48298
|
});
|
|
48264
48299
|
|
|
48265
48300
|
// src/lib/installer.ts
|
|
48266
|
-
import { existsSync as
|
|
48267
|
-
import { join as
|
|
48301
|
+
import { existsSync as existsSync10, readFileSync as readFileSync13, rmSync } from "fs";
|
|
48302
|
+
import { join as join20 } from "path";
|
|
48268
48303
|
import { homedir as homedir2 } from "os";
|
|
48269
48304
|
function getSkillPath(name) {
|
|
48270
48305
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
@@ -48274,7 +48309,7 @@ function getSkillPath(name) {
|
|
|
48274
48309
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
48275
48310
|
if (extensionPath)
|
|
48276
48311
|
return extensionPath;
|
|
48277
|
-
return
|
|
48312
|
+
return join20(getPortableSkillsRoot(), skillName);
|
|
48278
48313
|
}
|
|
48279
48314
|
function getCanonicalSkillName(name) {
|
|
48280
48315
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
@@ -48283,7 +48318,7 @@ function installSkill(name, options = {}) {
|
|
|
48283
48318
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
48284
48319
|
const canonicalName = getCanonicalSkillName(name);
|
|
48285
48320
|
const skillName = normalizeSkillName(canonicalName);
|
|
48286
|
-
if (!
|
|
48321
|
+
if (!existsSync10(getSkillPath(name))) {
|
|
48287
48322
|
const knownOfficial = Boolean(getSkill(name));
|
|
48288
48323
|
return {
|
|
48289
48324
|
skill: canonicalName,
|
|
@@ -48328,11 +48363,11 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
48328
48363
|
const base = projectDir || process.cwd();
|
|
48329
48364
|
switch (agent) {
|
|
48330
48365
|
case "pi":
|
|
48331
|
-
return scope === "project" ?
|
|
48366
|
+
return scope === "project" ? join20(base, ".pi", "skills") : join20(homedir2(), ".pi", "agent", "skills");
|
|
48332
48367
|
case "opencode":
|
|
48333
|
-
return scope === "project" ?
|
|
48368
|
+
return scope === "project" ? join20(base, ".opencode", "skills") : join20(homedir2(), ".config", "opencode", "skills");
|
|
48334
48369
|
default:
|
|
48335
|
-
return scope === "project" ?
|
|
48370
|
+
return scope === "project" ? join20(base, `.${agent}`, "skills") : join20(homedir2(), `.${agent}`, "skills");
|
|
48336
48371
|
}
|
|
48337
48372
|
}
|
|
48338
48373
|
function warnMissingDependencies(name, targetDir) {
|
|
@@ -48347,8 +48382,8 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
48347
48382
|
}
|
|
48348
48383
|
}
|
|
48349
48384
|
function readBundledSkillVersion(name) {
|
|
48350
|
-
const pkgPath =
|
|
48351
|
-
if (!
|
|
48385
|
+
const pkgPath = join20(getSkillPath(name), "package.json");
|
|
48386
|
+
if (!existsSync10(pkgPath))
|
|
48352
48387
|
return "unknown";
|
|
48353
48388
|
try {
|
|
48354
48389
|
const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
|
|
@@ -48415,13 +48450,13 @@ var init_skill_doc_file = __esm(() => {
|
|
|
48415
48450
|
});
|
|
48416
48451
|
|
|
48417
48452
|
// src/lib/skillinfo.ts
|
|
48418
|
-
import { existsSync as
|
|
48419
|
-
import { join as
|
|
48453
|
+
import { existsSync as existsSync11, readFileSync as readFileSync14 } from "fs";
|
|
48454
|
+
import { join as join21 } from "path";
|
|
48420
48455
|
function isInstructionSkillDir(skillPath, meta3) {
|
|
48421
48456
|
if (meta3?.kind === "instruction")
|
|
48422
48457
|
return true;
|
|
48423
|
-
const skillMdPath =
|
|
48424
|
-
if (!
|
|
48458
|
+
const skillMdPath = join21(skillPath, "SKILL.md");
|
|
48459
|
+
if (!existsSync11(skillMdPath))
|
|
48425
48460
|
return false;
|
|
48426
48461
|
try {
|
|
48427
48462
|
return parseSkillFrontmatter(readFileSync14(skillMdPath, "utf-8"))?.kind === "instruction";
|
|
@@ -48431,12 +48466,12 @@ function isInstructionSkillDir(skillPath, meta3) {
|
|
|
48431
48466
|
}
|
|
48432
48467
|
function getSkillDocs(name) {
|
|
48433
48468
|
const skillPath = getSkillPath(name);
|
|
48434
|
-
if (!
|
|
48469
|
+
if (!existsSync11(skillPath))
|
|
48435
48470
|
return null;
|
|
48436
48471
|
return {
|
|
48437
|
-
skillMd: readIfExists(
|
|
48438
|
-
readme: readIfExists(
|
|
48439
|
-
claudeMd: readIfExists(
|
|
48472
|
+
skillMd: readIfExists(join21(skillPath, "SKILL.md")),
|
|
48473
|
+
readme: readIfExists(join21(skillPath, "README.md")),
|
|
48474
|
+
claudeMd: readIfExists(join21(skillPath, "CLAUDE.md"))
|
|
48440
48475
|
};
|
|
48441
48476
|
}
|
|
48442
48477
|
function getSkillBestDoc(name, file2) {
|
|
@@ -48448,18 +48483,18 @@ function getSkillBestDoc(name, file2) {
|
|
|
48448
48483
|
}
|
|
48449
48484
|
function getSkillRequirements(name) {
|
|
48450
48485
|
const skillPath = getSkillPath(name);
|
|
48451
|
-
if (!
|
|
48486
|
+
if (!existsSync11(skillPath))
|
|
48452
48487
|
return null;
|
|
48453
48488
|
const texts = [];
|
|
48454
48489
|
for (const file2 of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
48455
|
-
const content = readIfExists(
|
|
48490
|
+
const content = readIfExists(join21(skillPath, file2));
|
|
48456
48491
|
if (content)
|
|
48457
48492
|
texts.push(content);
|
|
48458
48493
|
}
|
|
48459
48494
|
const meta3 = getSkill(name);
|
|
48460
48495
|
let dependencies = {};
|
|
48461
48496
|
try {
|
|
48462
|
-
dependencies = JSON.parse(readFileSync14(
|
|
48497
|
+
dependencies = JSON.parse(readFileSync14(join21(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
48463
48498
|
} catch {}
|
|
48464
48499
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta3);
|
|
48465
48500
|
}
|
|
@@ -48512,7 +48547,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
48512
48547
|
const meta3 = getSkill(name);
|
|
48513
48548
|
const canonicalName = meta3?.name ?? name;
|
|
48514
48549
|
const skillPath = getSkillPath(canonicalName);
|
|
48515
|
-
if (!
|
|
48550
|
+
if (!existsSync11(skillPath)) {
|
|
48516
48551
|
return { exitCode: 1, error: `Skill '${name}' not found` };
|
|
48517
48552
|
}
|
|
48518
48553
|
if (isInstructionSkillDir(skillPath, meta3)) {
|
|
@@ -48521,8 +48556,8 @@ async function runSkill(name, args, options = {}) {
|
|
|
48521
48556
|
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'.`
|
|
48522
48557
|
};
|
|
48523
48558
|
}
|
|
48524
|
-
const pkgPath =
|
|
48525
|
-
if (!
|
|
48559
|
+
const pkgPath = join21(skillPath, "package.json");
|
|
48560
|
+
if (!existsSync11(pkgPath)) {
|
|
48526
48561
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
48527
48562
|
}
|
|
48528
48563
|
let entryPoint2;
|
|
@@ -48541,12 +48576,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
48541
48576
|
} catch {
|
|
48542
48577
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
48543
48578
|
}
|
|
48544
|
-
const entryPath =
|
|
48545
|
-
if (!
|
|
48579
|
+
const entryPath = join21(skillPath, entryPoint2);
|
|
48580
|
+
if (!existsSync11(entryPath)) {
|
|
48546
48581
|
return { exitCode: 1, error: `Entry point '${entryPoint2}' not found in skill '${name}'` };
|
|
48547
48582
|
}
|
|
48548
48583
|
const env = { ...process.env, ...options.env };
|
|
48549
|
-
if (!
|
|
48584
|
+
if (!existsSync11(join21(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
|
|
48550
48585
|
const failure = await prepareSkillDependencies(skillPath, env, options.preparationTimeoutMs);
|
|
48551
48586
|
if (failure)
|
|
48552
48587
|
return failure;
|
|
@@ -48572,7 +48607,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
48572
48607
|
function detectProjectSkills(cwd = process.cwd()) {
|
|
48573
48608
|
let pkg;
|
|
48574
48609
|
try {
|
|
48575
|
-
pkg = JSON.parse(readFileSync14(
|
|
48610
|
+
pkg = JSON.parse(readFileSync14(join21(cwd, "package.json"), "utf8"));
|
|
48576
48611
|
} catch {
|
|
48577
48612
|
return { detected: [], recommended: [] };
|
|
48578
48613
|
}
|
|
@@ -48610,7 +48645,7 @@ function extractEnvVars(text2) {
|
|
|
48610
48645
|
}
|
|
48611
48646
|
function readIfExists(path) {
|
|
48612
48647
|
try {
|
|
48613
|
-
if (
|
|
48648
|
+
if (existsSync11(path)) {
|
|
48614
48649
|
return readFileSync14(path, "utf-8");
|
|
48615
48650
|
}
|
|
48616
48651
|
} catch {}
|
|
@@ -48667,6 +48702,8 @@ var init_selected_document = __esm(() => {
|
|
|
48667
48702
|
async function resolveSelectionContext(profileId, options = {}) {
|
|
48668
48703
|
const sessionState = options.sessionId ? readSkillSessionSnapshotIfExists(options.sessionId, options) : null;
|
|
48669
48704
|
const session = sessionState?.receipt ?? null;
|
|
48705
|
+
if (options.nativeParentSessionId !== undefined && session && (session.parent?.sessionId ?? null) !== options.nativeParentSessionId)
|
|
48706
|
+
throw new SkillSelectionError("SESSION_PARENT_MISMATCH", "The native session id is already bound to different parent custody.");
|
|
48670
48707
|
const parentState = !session && options.parentSessionId ? readSkillSessionSnapshotIfExists(options.parentSessionId, options) : null;
|
|
48671
48708
|
if (!session && options.parentSessionId && !parentState) {
|
|
48672
48709
|
throw new SkillSelectionError("SESSION_PARENT_NOT_FOUND", "A child Skills session requires an existing parent receipt so its inherited pin can be bound exactly.");
|
|
@@ -48860,11 +48897,11 @@ var init_plugin_projection = __esm(() => {
|
|
|
48860
48897
|
});
|
|
48861
48898
|
|
|
48862
48899
|
// src/lib/plugin-projection-store.ts
|
|
48863
|
-
import { constants as constants7, closeSync as closeSync10, fchmodSync, fstatSync as fstatSync10, fsyncSync as fsyncSync2, linkSync, lstatSync as
|
|
48864
|
-
import { dirname as dirname11, isAbsolute as isAbsolute9, join as
|
|
48900
|
+
import { constants as constants7, closeSync as closeSync10, fchmodSync, fstatSync as fstatSync10, fsyncSync as fsyncSync2, linkSync, lstatSync as lstatSync14, 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";
|
|
48901
|
+
import { dirname as dirname11, isAbsolute as isAbsolute9, join as join22, parse as parse9, resolve as resolve11 } from "path";
|
|
48865
48902
|
function stat(path) {
|
|
48866
48903
|
try {
|
|
48867
|
-
return
|
|
48904
|
+
return lstatSync14(path, { bigint: true });
|
|
48868
48905
|
} catch (error61) {
|
|
48869
48906
|
if (missing(error61))
|
|
48870
48907
|
return null;
|
|
@@ -48872,7 +48909,7 @@ function stat(path) {
|
|
|
48872
48909
|
}
|
|
48873
48910
|
}
|
|
48874
48911
|
function canonical5(path) {
|
|
48875
|
-
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute9(path) &&
|
|
48912
|
+
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute9(path) && resolve11(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
48876
48913
|
}
|
|
48877
48914
|
function owner(stats, system = false) {
|
|
48878
48915
|
const current = uid();
|
|
@@ -48887,7 +48924,7 @@ function ancestors(path, create = false) {
|
|
|
48887
48924
|
let current = filesystemRoot;
|
|
48888
48925
|
for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
|
|
48889
48926
|
if (segment)
|
|
48890
|
-
current =
|
|
48927
|
+
current = join22(current, segment);
|
|
48891
48928
|
let currentStat = stat(current);
|
|
48892
48929
|
if (!currentStat && create) {
|
|
48893
48930
|
try {
|
|
@@ -48995,7 +49032,7 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
48995
49032
|
pluginNeed(++visited <= PLUGIN_PROJECTION_LIMITS.files * 50, "Plugin tree membership exceeds its limit");
|
|
48996
49033
|
const path = relative5 ? `${relative5}/${name}` : name;
|
|
48997
49034
|
pluginNeed(new TextEncoder().encode(path).byteLength <= 100 && !/[\\:\x00-\x1f\x7f]/u.test(path), "Plugin entry path exceeds its limit or is unsafe");
|
|
48998
|
-
const absolute =
|
|
49035
|
+
const absolute = join22(directory, name), entryStat = stat(absolute);
|
|
48999
49036
|
pluginNeed(entryStat, "Plugin tree member disappeared");
|
|
49000
49037
|
if (relative5 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
|
|
49001
49038
|
const bytes2 = readBytes(absolute, 32, "native-pin");
|
|
@@ -49012,7 +49049,7 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
49012
49049
|
directories.push({ path: absolute, stat: entryStat, names: pins });
|
|
49013
49050
|
for (const pin of pins) {
|
|
49014
49051
|
pluginNeed(/^[1-9][0-9]{0,9}$/.test(pin) && Number(pin) <= 2147483647, "Unrecognized native plugin pin name");
|
|
49015
|
-
const pinPath =
|
|
49052
|
+
const pinPath = join22(absolute, pin), pinStat = stat(pinPath);
|
|
49016
49053
|
pluginNeed(pinStat, "Native plugin pin disappeared");
|
|
49017
49054
|
const bytes2 = readBytes(pinPath, 4096, "native-pin");
|
|
49018
49055
|
let value;
|
|
@@ -49109,7 +49146,7 @@ var init_selected_manifest = __esm(() => {
|
|
|
49109
49146
|
});
|
|
49110
49147
|
|
|
49111
49148
|
// src/lib/plugin-admission.ts
|
|
49112
|
-
import { isAbsolute as isAbsolute10, join as
|
|
49149
|
+
import { isAbsolute as isAbsolute10, join as join23, resolve as resolve12 } from "path";
|
|
49113
49150
|
function validatePluginTarget(value) {
|
|
49114
49151
|
pluginKeys(value, ["schemaVersion", "pluginId", "registrations", "native", "resolver"]);
|
|
49115
49152
|
pluginNeed(value.schemaVersion === 1, "Invalid plugin admission target");
|
|
@@ -49119,7 +49156,7 @@ function validatePluginTarget(value) {
|
|
|
49119
49156
|
for (const registration of value.registrations) {
|
|
49120
49157
|
pluginKeys(registration, ["scope", "projectPath"]);
|
|
49121
49158
|
pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
|
|
49122
|
-
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute10(registration.projectPath) &&
|
|
49159
|
+
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute10(registration.projectPath) && resolve12(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
|
|
49123
49160
|
const key = JSON.stringify([registration.scope, registration.projectPath]);
|
|
49124
49161
|
pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
|
|
49125
49162
|
scopes.add(key);
|
|
@@ -49127,7 +49164,7 @@ function validatePluginTarget(value) {
|
|
|
49127
49164
|
for (const key of ["native", "resolver"]) {
|
|
49128
49165
|
pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
|
|
49129
49166
|
pluginText(value[key].executable);
|
|
49130
|
-
pluginNeed(isAbsolute10(value[key].executable) &&
|
|
49167
|
+
pluginNeed(isAbsolute10(value[key].executable) && resolve12(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
|
|
49131
49168
|
pluginDigest(value[key].digest);
|
|
49132
49169
|
}
|
|
49133
49170
|
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)");
|
|
@@ -49270,12 +49307,12 @@ function pluginResolverCommand(binding) {
|
|
|
49270
49307
|
}
|
|
49271
49308
|
function pluginBindingPath(storeRoot, id) {
|
|
49272
49309
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
49273
|
-
return
|
|
49310
|
+
return join23(storeRoot, "bindings", `${id}.json`);
|
|
49274
49311
|
}
|
|
49275
49312
|
function pluginReceiptPath(storeRoot, id, digest) {
|
|
49276
49313
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
49277
49314
|
pluginDigest(digest);
|
|
49278
|
-
return
|
|
49315
|
+
return join23(storeRoot, "receipts", id, `${digest.slice(7)}.json`);
|
|
49279
49316
|
}
|
|
49280
49317
|
function readPluginBinding(storeRoot, id) {
|
|
49281
49318
|
const value = readPluginJson(pluginBindingPath(storeRoot, id));
|
|
@@ -49295,7 +49332,7 @@ function readPluginAdmissionReceipt(storeRoot, id, digest) {
|
|
|
49295
49332
|
pluginNeed(receipt.plan.bindingId === id && receipt.plan.planDigest === digest, "Plugin receipt identity differs from its filename");
|
|
49296
49333
|
const binding = readPluginBinding(storeRoot, id);
|
|
49297
49334
|
pluginNeed(canonicalJson(binding) === canonicalJson(receipt.plan.binding) && receipt.plan.sourceCommand === pluginResolverCommand(binding), "Plugin receipt binding changed");
|
|
49298
|
-
pluginNeed(receipt.materializedPath ===
|
|
49335
|
+
pluginNeed(receipt.materializedPath === join23(storeRoot, "objects", id, digest.slice(7)), "Plugin receipt points outside its immutable materialization");
|
|
49299
49336
|
pluginText(receipt.admittedAt, 64);
|
|
49300
49337
|
pluginNeed(Number.isFinite(Date.parse(receipt.admittedAt)), "Invalid plugin admission time");
|
|
49301
49338
|
return receipt;
|
|
@@ -49312,8 +49349,8 @@ var init_plugin_admission = __esm(() => {
|
|
|
49312
49349
|
});
|
|
49313
49350
|
|
|
49314
49351
|
// src/lib/plugin-discovery.ts
|
|
49315
|
-
import { closeSync as closeSync11, constants as constants8, fstatSync as fstatSync11, lstatSync as
|
|
49316
|
-
import { basename as basename6, dirname as dirname12, isAbsolute as isAbsolute11, join as
|
|
49352
|
+
import { closeSync as closeSync11, constants as constants8, fstatSync as fstatSync11, lstatSync as lstatSync15, openSync as openSync11, opendirSync as opendirSync3, readSync as readSync7 } from "fs";
|
|
49353
|
+
import { basename as basename6, dirname as dirname12, isAbsolute as isAbsolute11, join as join24, resolve as resolve13 } from "path";
|
|
49317
49354
|
function validateManagedPluginWitnesses(value) {
|
|
49318
49355
|
pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
|
|
49319
49356
|
const seen = new Set;
|
|
@@ -49322,21 +49359,21 @@ function validateManagedPluginWitnesses(value) {
|
|
|
49322
49359
|
pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
|
|
49323
49360
|
seen.add(item.bindingId);
|
|
49324
49361
|
pluginText(item.storeRoot);
|
|
49325
|
-
pluginNeed(isAbsolute11(item.storeRoot) &&
|
|
49362
|
+
pluginNeed(isAbsolute11(item.storeRoot) && resolve13(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
|
|
49326
49363
|
}
|
|
49327
49364
|
}
|
|
49328
49365
|
function safe3(path) {
|
|
49329
49366
|
pluginText(path);
|
|
49330
|
-
pluginNeed(isAbsolute11(path) &&
|
|
49367
|
+
pluginNeed(isAbsolute11(path) && resolve13(path) === path, "Invalid plugin registry path");
|
|
49331
49368
|
for (let at = path;; at = dirname12(at)) {
|
|
49332
|
-
pluginNeed(!
|
|
49369
|
+
pluginNeed(!lstatSync15(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
49333
49370
|
if (at === dirname12(at))
|
|
49334
49371
|
break;
|
|
49335
49372
|
}
|
|
49336
49373
|
}
|
|
49337
49374
|
function readRegistry(path) {
|
|
49338
49375
|
safe3(path);
|
|
49339
|
-
const initial =
|
|
49376
|
+
const initial = lstatSync15(path);
|
|
49340
49377
|
pluginNeed(initial.isFile() && initial.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
|
|
49341
49378
|
const fd = openSync11(path, constants8.O_RDONLY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK);
|
|
49342
49379
|
try {
|
|
@@ -49350,7 +49387,7 @@ function readRegistry(path) {
|
|
|
49350
49387
|
break;
|
|
49351
49388
|
length += count;
|
|
49352
49389
|
}
|
|
49353
|
-
const after = fstatSync11(fd), current =
|
|
49390
|
+
const after = fstatSync11(fd), current = lstatSync15(path);
|
|
49354
49391
|
safe3(path);
|
|
49355
49392
|
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");
|
|
49356
49393
|
let value;
|
|
@@ -49380,7 +49417,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
49380
49417
|
seen.add(target.pluginId);
|
|
49381
49418
|
const rows = plugins[target.pluginId];
|
|
49382
49419
|
pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
|
|
49383
|
-
const [name, market] = target.pluginId.split("@"), cacheRoot =
|
|
49420
|
+
const [name, market] = target.pluginId.split("@"), cacheRoot = join24(dirname12(path), "cache", market, name);
|
|
49384
49421
|
const scopes = new Set, approvals = new Map, currentFiles = new Map;
|
|
49385
49422
|
plugins[target.pluginId] = rows.map((row) => {
|
|
49386
49423
|
pluginNeed(pluginObject(row), "Invalid managed plugin registration");
|
|
@@ -49393,7 +49430,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
49393
49430
|
pluginText(row.sourceProducerPath);
|
|
49394
49431
|
pluginText(row.lastUpdated, 64);
|
|
49395
49432
|
pluginNeed(Number.isFinite(Date.parse(row.lastUpdated)), "Invalid managed plugin update timestamp");
|
|
49396
|
-
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath ===
|
|
49433
|
+
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join24(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
49397
49434
|
const approval = (producer) => {
|
|
49398
49435
|
pluginText(producer);
|
|
49399
49436
|
const digest = `sha256:${basename6(producer)}`;
|
|
@@ -49423,7 +49460,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
49423
49460
|
return Object.fromEntries(Object.entries(row).filter(([key]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key)));
|
|
49424
49461
|
});
|
|
49425
49462
|
safe3(cacheRoot);
|
|
49426
|
-
const before =
|
|
49463
|
+
const before = lstatSync15(cacheRoot);
|
|
49427
49464
|
pluginNeed(before.isDirectory(), "Invalid managed plugin cache root");
|
|
49428
49465
|
const directory = opendirSync3(cacheRoot), names = [];
|
|
49429
49466
|
try {
|
|
@@ -49436,17 +49473,17 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
49436
49473
|
directory.closeSync();
|
|
49437
49474
|
}
|
|
49438
49475
|
for (const version2 of names.sort()) {
|
|
49439
|
-
const files = pluginFileWitnesses(snapshotPluginTree(
|
|
49476
|
+
const files = pluginFileWitnesses(snapshotPluginTree(join24(cacheRoot, version2), { nativeRuntime: `claude-${target.native.version}` }));
|
|
49440
49477
|
verifiedBytes += files.reduce((total, file2) => total + file2.size, 0);
|
|
49441
49478
|
pluginNeed(verifiedBytes <= 256 * 1024 * 1024, "Managed plugin verification exceeds its aggregate byte budget");
|
|
49442
49479
|
const serialized = JSON.stringify(files);
|
|
49443
|
-
const expected = currentFiles.get(
|
|
49480
|
+
const expected = currentFiles.get(join24(cacheRoot, version2));
|
|
49444
49481
|
pluginNeed(expected === undefined || serialized === expected, "Current native cache differs from its exact registered producer receipt");
|
|
49445
49482
|
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");
|
|
49446
49483
|
}
|
|
49447
49484
|
for (const row of rows)
|
|
49448
49485
|
pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
|
|
49449
|
-
const after =
|
|
49486
|
+
const after = lstatSync15(cacheRoot);
|
|
49450
49487
|
safe3(cacheRoot);
|
|
49451
49488
|
pluginNeed(before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs, "Managed cache version membership changed during verification");
|
|
49452
49489
|
}
|
|
@@ -49461,19 +49498,19 @@ var init_plugin_discovery = __esm(() => {
|
|
|
49461
49498
|
|
|
49462
49499
|
// src/lib/claude-marketplace-registry.ts
|
|
49463
49500
|
import { createHash as createHash13 } from "crypto";
|
|
49464
|
-
import { closeSync as closeSync12, constants as constants9, fstatSync as fstatSync12, lstatSync as
|
|
49465
|
-
import { basename as basename7, dirname as dirname13, isAbsolute as isAbsolute12, resolve as
|
|
49501
|
+
import { closeSync as closeSync12, constants as constants9, fstatSync as fstatSync12, lstatSync as lstatSync16, openSync as openSync12, readSync as readSync8 } from "fs";
|
|
49502
|
+
import { basename as basename7, dirname as dirname13, isAbsolute as isAbsolute12, resolve as resolve14 } from "path";
|
|
49466
49503
|
function need5(value, reason) {
|
|
49467
49504
|
if (!value)
|
|
49468
49505
|
throw new Error(`Claude marketplace registry ${reason}`);
|
|
49469
49506
|
}
|
|
49470
49507
|
function absolutePath2(value) {
|
|
49471
|
-
need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute12(value) &&
|
|
49508
|
+
need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute12(value) && resolve14(value) === value, "requires a normalized absolute path");
|
|
49472
49509
|
}
|
|
49473
49510
|
function parents2(path) {
|
|
49474
49511
|
const result = [];
|
|
49475
49512
|
for (let at = dirname13(path);; at = dirname13(at)) {
|
|
49476
|
-
const stat2 =
|
|
49513
|
+
const stat2 = lstatSync16(at, { bigint: true });
|
|
49477
49514
|
need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
49478
49515
|
result.push([at, stat2]);
|
|
49479
49516
|
if (at === dirname13(at))
|
|
@@ -49484,7 +49521,7 @@ function readRegistry2(path, budget) {
|
|
|
49484
49521
|
absolutePath2(path);
|
|
49485
49522
|
need5(basename7(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
49486
49523
|
need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
|
|
49487
|
-
const ancestors2 = parents2(path), initial =
|
|
49524
|
+
const ancestors2 = parents2(path), initial = lstatSync16(path, { bigint: true });
|
|
49488
49525
|
need5(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
49489
49526
|
need5(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
|
|
49490
49527
|
const fd = openSync12(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
|
|
@@ -49499,10 +49536,10 @@ function readRegistry2(path, budget) {
|
|
|
49499
49536
|
break;
|
|
49500
49537
|
length += count;
|
|
49501
49538
|
}
|
|
49502
|
-
const after = fstatSync12(fd, { bigint: true }), current =
|
|
49539
|
+
const after = fstatSync12(fd, { bigint: true }), current = lstatSync16(path, { bigint: true });
|
|
49503
49540
|
need5(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
49504
49541
|
for (const [ancestor, before] of ancestors2) {
|
|
49505
|
-
const now =
|
|
49542
|
+
const now = lstatSync16(ancestor, { bigint: true });
|
|
49506
49543
|
need5(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
49507
49544
|
}
|
|
49508
49545
|
budget.remaining -= length;
|
|
@@ -49642,7 +49679,7 @@ var init_claude_marketplace_registry = __esm(() => {
|
|
|
49642
49679
|
});
|
|
49643
49680
|
|
|
49644
49681
|
// src/lib/codex-hook-trust-files.ts
|
|
49645
|
-
import { closeSync as closeSync13, constants as constants10, fstatSync as fstatSync13, fsyncSync as fsyncSync3, lstatSync as
|
|
49682
|
+
import { closeSync as closeSync13, constants as constants10, fstatSync as fstatSync13, fsyncSync as fsyncSync3, lstatSync as lstatSync17, openSync as openSync13, readSync as readSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
49646
49683
|
import { createHash as createHash14 } from "crypto";
|
|
49647
49684
|
import { dirname as dirname14 } from "path";
|
|
49648
49685
|
function need6(value, code) {
|
|
@@ -49651,7 +49688,7 @@ function need6(value, code) {
|
|
|
49651
49688
|
}
|
|
49652
49689
|
function safeParents(file2) {
|
|
49653
49690
|
for (let p = dirname14(file2);; p = dirname14(p)) {
|
|
49654
|
-
const s =
|
|
49691
|
+
const s = lstatSync17(p);
|
|
49655
49692
|
need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
|
|
49656
49693
|
need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
49657
49694
|
if (dirname14(p) === p)
|
|
@@ -49661,7 +49698,7 @@ function safeParents(file2) {
|
|
|
49661
49698
|
function snapshot(file2, privateFile = false, options = {}) {
|
|
49662
49699
|
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
49663
49700
|
safeParents(file2);
|
|
49664
|
-
const initial =
|
|
49701
|
+
const initial = lstatSync17(file2, { bigint: true });
|
|
49665
49702
|
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");
|
|
49666
49703
|
need6(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
49667
49704
|
const fd = openSync13(file2, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
@@ -49676,7 +49713,7 @@ function snapshot(file2, privateFile = false, options = {}) {
|
|
|
49676
49713
|
break;
|
|
49677
49714
|
length += n2;
|
|
49678
49715
|
}
|
|
49679
|
-
need6(length === Number(before.size) && sameStat(before, fstatSync13(fd, { bigint: true })) && sameStat(before,
|
|
49716
|
+
need6(length === Number(before.size) && sameStat(before, fstatSync13(fd, { bigint: true })) && sameStat(before, lstatSync17(file2, { bigint: true })), "INPUT_CHANGED");
|
|
49680
49717
|
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
49681
49718
|
return { file: file2, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash14("sha256").update(content).digest("hex") };
|
|
49682
49719
|
} finally {
|
|
@@ -49731,8 +49768,8 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
49731
49768
|
|
|
49732
49769
|
// src/lib/agent-discovery.ts
|
|
49733
49770
|
import { createHash as createHash16 } from "crypto";
|
|
49734
|
-
import { lstatSync as
|
|
49735
|
-
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute13, join as
|
|
49771
|
+
import { lstatSync as lstatSync18, readFileSync as readFileSync15, readdirSync as readdirSync7, realpathSync as realpathSync5 } from "fs";
|
|
49772
|
+
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute13, join as join25, resolve as resolve15, sep as sep5 } from "path";
|
|
49736
49773
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
|
|
49737
49774
|
function parseConfig(text2, path, toml = false) {
|
|
49738
49775
|
try {
|
|
@@ -49748,7 +49785,7 @@ function safe4(path) {
|
|
|
49748
49785
|
if (!isAbsolute13(path) || path.includes("\x00"))
|
|
49749
49786
|
throw new Error("Expected an absolute native discovery path");
|
|
49750
49787
|
for (let cursor = path;; cursor = dirname15(cursor)) {
|
|
49751
|
-
if (
|
|
49788
|
+
if (lstatSync18(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
49752
49789
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
49753
49790
|
if (dirname15(cursor) === cursor)
|
|
49754
49791
|
break;
|
|
@@ -49758,7 +49795,7 @@ function read(path, changes) {
|
|
|
49758
49795
|
safe4(path);
|
|
49759
49796
|
if (changes?.has(path))
|
|
49760
49797
|
return changes.get(path);
|
|
49761
|
-
const stat2 =
|
|
49798
|
+
const stat2 = lstatSync18(path, { throwIfNoEntry: false });
|
|
49762
49799
|
if (!stat2)
|
|
49763
49800
|
return null;
|
|
49764
49801
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
@@ -49869,12 +49906,12 @@ function codexInstallationRoots(binding) {
|
|
|
49869
49906
|
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)
|
|
49870
49907
|
throw new Error("Invalid native installation input proof");
|
|
49871
49908
|
const cache = dirname15(dirname15(proof.plugins[0].pluginParent));
|
|
49872
|
-
const config2 =
|
|
49909
|
+
const config2 = join25(dirname15(dirname15(cache)), "config.toml"), home = dirname15(dirname15(dirname15(cache)));
|
|
49873
49910
|
const configSource = binding.sources.find((source) => source.path === config2 && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
49874
|
-
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) =>
|
|
49911
|
+
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join25(home, path));
|
|
49875
49912
|
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)))))
|
|
49876
49913
|
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
49877
|
-
if (proof.plugins.some((input2) => dirname15(dirname15(input2.pluginParent)) !== cache || !binding.sources.some((source) => source.path ===
|
|
49914
|
+
if (proof.plugins.some((input2) => dirname15(dirname15(input2.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join25(input2.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
49878
49915
|
throw new Error("Missing native installation input source witness");
|
|
49879
49916
|
return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
|
|
49880
49917
|
const text2 = read(path);
|
|
@@ -49892,10 +49929,12 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
49892
49929
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
49893
49930
|
}
|
|
49894
49931
|
function agentDiscoveryConfigPath(home, agent) {
|
|
49895
|
-
|
|
49932
|
+
if (agent === "sumi")
|
|
49933
|
+
return sumiConfigPath(home);
|
|
49934
|
+
return join25(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
49896
49935
|
}
|
|
49897
49936
|
function resolveAgentDiscovery(options) {
|
|
49898
|
-
const canonical6 = options.canonical ??
|
|
49937
|
+
const canonical6 = options.canonical ?? resolve15, home = resolve15(options.home), agent = options.agent;
|
|
49899
49938
|
const sources = [], roots = new Set, builtinNames = [];
|
|
49900
49939
|
const witness = (path, format, fields2) => {
|
|
49901
49940
|
const source = { path: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
|
|
@@ -49906,13 +49945,49 @@ function resolveAgentDiscovery(options) {
|
|
|
49906
49945
|
if (agent === "hermes")
|
|
49907
49946
|
assertHermesEnvironment(home);
|
|
49908
49947
|
const configPath = agentDiscoveryConfigPath(home, agent);
|
|
49909
|
-
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : ["version"]);
|
|
49948
|
+
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : agent === "sumi" ? ["skills", "plugin", "plugins", "permissions"] : ["version"]);
|
|
49910
49949
|
const config2 = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
|
|
49911
49950
|
const unresolved = (detail) => {
|
|
49912
49951
|
throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
|
|
49913
49952
|
};
|
|
49953
|
+
if (agent === "sumi") {
|
|
49954
|
+
const directory = sumiConfigDirectory(home);
|
|
49955
|
+
if (witness(join25(directory, "sumi.jsonc")) !== null)
|
|
49956
|
+
unresolved("JSONC configuration requires a supported format adapter");
|
|
49957
|
+
for (const root of [directory, join25(home, ".claude"), join25(home, ".agents")])
|
|
49958
|
+
for (const name of ["skill", "skills"])
|
|
49959
|
+
roots.add(join25(root, name));
|
|
49960
|
+
if (config2.skills !== undefined && (!Array.isArray(config2.skills) || config2.skills.some((path) => typeof path !== "string")))
|
|
49961
|
+
unresolved("skills must be a string array");
|
|
49962
|
+
for (const value of config2.skills ?? []) {
|
|
49963
|
+
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute13(value) || value.startsWith("~/")))
|
|
49964
|
+
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
49965
|
+
roots.add(value.startsWith("~/") ? join25(home, value.slice(2)) : value);
|
|
49966
|
+
}
|
|
49967
|
+
for (const key of ["plugin", "plugins"])
|
|
49968
|
+
if (config2[key] !== undefined && !Array.isArray(config2[key]))
|
|
49969
|
+
unresolved(`${key} must be an array`);
|
|
49970
|
+
const plugins = [join25(directory, "plugin"), join25(directory, "plugins")];
|
|
49971
|
+
for (const path of plugins) {
|
|
49972
|
+
safe4(path);
|
|
49973
|
+
if (lstatSync18(path, { throwIfNoEntry: false })?.isDirectory())
|
|
49974
|
+
for (const name of readdirSync7(path).sort()) {
|
|
49975
|
+
if (name === "skills-cli.js" && path === plugins[1])
|
|
49976
|
+
continue;
|
|
49977
|
+
const target = join25(path, name);
|
|
49978
|
+
if (!lstatSync18(target).isFile())
|
|
49979
|
+
unresolved("local plugin packages need a dedicated discovery adapter");
|
|
49980
|
+
witness(target);
|
|
49981
|
+
}
|
|
49982
|
+
}
|
|
49983
|
+
for (const root of roots) {
|
|
49984
|
+
safe4(root);
|
|
49985
|
+
if (lstatSync18(root, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(root).some((name) => name.endsWith(".md")))
|
|
49986
|
+
unresolved("flat markdown skills require a dedicated native migration adapter");
|
|
49987
|
+
}
|
|
49988
|
+
}
|
|
49914
49989
|
if (agent === "hermes") {
|
|
49915
|
-
const profile = witness(
|
|
49990
|
+
const profile = witness(join25(home, ".hermes/active_profile"));
|
|
49916
49991
|
if (profile?.trim() && profile.trim() !== "default")
|
|
49917
49992
|
unresolved("a non-default profile is active");
|
|
49918
49993
|
const declared = config2.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
|
|
@@ -49926,7 +50001,7 @@ function resolveAgentDiscovery(options) {
|
|
|
49926
50001
|
continue;
|
|
49927
50002
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
49928
50003
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
49929
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ?
|
|
50004
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join25(home, normalized.slice(2)) : resolve15(home, ".hermes", normalized);
|
|
49930
50005
|
safe4(path);
|
|
49931
50006
|
roots.add(path);
|
|
49932
50007
|
}
|
|
@@ -49935,8 +50010,8 @@ function resolveAgentDiscovery(options) {
|
|
|
49935
50010
|
const executable = Bun.which("gemini");
|
|
49936
50011
|
if (executable) {
|
|
49937
50012
|
let packageRoot;
|
|
49938
|
-
for (let directory = dirname15(
|
|
49939
|
-
const path =
|
|
50013
|
+
for (let directory = dirname15(realpathSync5(executable)), depth = 0;depth < 8; directory = dirname15(directory), depth++) {
|
|
50014
|
+
const path = join25(directory, "package.json"), raw = read(path);
|
|
49940
50015
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
49941
50016
|
packageRoot = directory;
|
|
49942
50017
|
witness(path);
|
|
@@ -49947,12 +50022,12 @@ function resolveAgentDiscovery(options) {
|
|
|
49947
50022
|
}
|
|
49948
50023
|
if (!packageRoot)
|
|
49949
50024
|
unresolved("installed Gemini package layout is not recognized");
|
|
49950
|
-
const builtinRoot =
|
|
50025
|
+
const builtinRoot = join25(packageRoot, "bundle/builtin");
|
|
49951
50026
|
safe4(builtinRoot);
|
|
49952
|
-
if (!
|
|
50027
|
+
if (!lstatSync18(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
49953
50028
|
unresolved("installed Gemini builtin root is missing");
|
|
49954
50029
|
for (const name of readdirSync7(builtinRoot).sort()) {
|
|
49955
|
-
const text2 = witness(
|
|
50030
|
+
const text2 = witness(join25(builtinRoot, name, "SKILL.md"));
|
|
49956
50031
|
const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
|
|
49957
50032
|
if (!match?.[1] || builtinNames.includes(match[1]))
|
|
49958
50033
|
unresolved("installed Gemini builtin name is missing or ambiguous");
|
|
@@ -49994,39 +50069,39 @@ function resolveAgentDiscovery(options) {
|
|
|
49994
50069
|
function plugin(root) {
|
|
49995
50070
|
root = canonical6(root);
|
|
49996
50071
|
safe4(root);
|
|
49997
|
-
const manifestPath =
|
|
50072
|
+
const manifestPath = join25(root, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
49998
50073
|
const raw = witness(manifestPath);
|
|
49999
50074
|
if (raw === null)
|
|
50000
50075
|
unresolved("plugin manifest missing");
|
|
50001
50076
|
const manifest = parseConfig(raw, manifestPath);
|
|
50002
|
-
const hooks = witness(
|
|
50077
|
+
const hooks = witness(join25(root, "hooks/hooks.json"));
|
|
50003
50078
|
if (manifest.hooks !== undefined || hooks !== null)
|
|
50004
50079
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
50005
|
-
const commands =
|
|
50080
|
+
const commands = join25(root, "commands");
|
|
50006
50081
|
safe4(commands);
|
|
50007
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
50082
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length))
|
|
50008
50083
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
50009
|
-
const rootSkill = witness(
|
|
50084
|
+
const rootSkill = witness(join25(root, "SKILL.md"));
|
|
50010
50085
|
if (rootSkill !== null)
|
|
50011
50086
|
roots.add(root);
|
|
50012
50087
|
const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
50013
50088
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
50014
50089
|
unresolved("unsupported plugin skill paths");
|
|
50015
50090
|
if (agent === "claude")
|
|
50016
|
-
roots.add(
|
|
50091
|
+
roots.add(join25(root, "skills"));
|
|
50017
50092
|
for (const value of declared) {
|
|
50018
|
-
const path =
|
|
50093
|
+
const path = resolve15(root, value);
|
|
50019
50094
|
if (path !== root && !path.startsWith(root + sep5))
|
|
50020
50095
|
unresolved("plugin skill path escapes its root");
|
|
50021
50096
|
roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname15(path) : path);
|
|
50022
50097
|
}
|
|
50023
50098
|
}
|
|
50024
50099
|
if (agent === "claude") {
|
|
50025
|
-
const registrations = witness(
|
|
50026
|
-
const installed = registrations === null ? {} : parseConfig(registrations,
|
|
50027
|
-
const commands = canonical6(
|
|
50100
|
+
const registrations = witness(join25(home, ".claude/plugins/installed_plugins.json"));
|
|
50101
|
+
const installed = registrations === null ? {} : parseConfig(registrations, join25(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
50102
|
+
const commands = canonical6(join25(home, ".claude/commands"));
|
|
50028
50103
|
safe4(commands);
|
|
50029
|
-
if (
|
|
50104
|
+
if (lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
|
|
50030
50105
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
50031
50106
|
for (const [id, enabled] of Object.entries(config2.enabledPlugins ?? {})) {
|
|
50032
50107
|
if (enabled === false)
|
|
@@ -50048,16 +50123,16 @@ function resolveAgentDiscovery(options) {
|
|
|
50048
50123
|
const market = config2.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
50049
50124
|
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute13(market.source))
|
|
50050
50125
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
50051
|
-
const catalogText = witness(
|
|
50126
|
+
const catalogText = witness(join25(market.source, ".agents/plugins/marketplace.json"));
|
|
50052
50127
|
if (catalogText === null)
|
|
50053
50128
|
unresolved("marketplace catalog missing");
|
|
50054
|
-
const catalog = parseConfig(catalogText,
|
|
50129
|
+
const catalog = parseConfig(catalogText, join25(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
50055
50130
|
if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
|
|
50056
50131
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
50057
|
-
plugin(
|
|
50132
|
+
plugin(resolve15(market.source, matches[0].source.path));
|
|
50058
50133
|
}
|
|
50059
50134
|
} else if (agent === "opencode") {
|
|
50060
|
-
if (witness(
|
|
50135
|
+
if (witness(join25(home, ".config/opencode/opencode.jsonc")) !== null || witness(join25(home, ".config/opencode/config.json")) !== null)
|
|
50061
50136
|
unresolved("additional config layers require review");
|
|
50062
50137
|
if ((config2.plugin?.length ?? 0) > 0 || config2.skills?.urls?.length)
|
|
50063
50138
|
unresolved("external plugin or remote skill source");
|
|
@@ -50066,14 +50141,17 @@ function resolveAgentDiscovery(options) {
|
|
|
50066
50141
|
unresolved("relative or malformed added skill root");
|
|
50067
50142
|
roots.add(path);
|
|
50068
50143
|
}
|
|
50069
|
-
const localPlugins =
|
|
50144
|
+
const localPlugins = join25(home, ".config/opencode/plugins");
|
|
50070
50145
|
safe4(localPlugins);
|
|
50071
|
-
if (
|
|
50146
|
+
if (lstatSync18(localPlugins, { throwIfNoEntry: false }) && readdirSync7(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
50072
50147
|
unresolved("additional local plugin hooks require review");
|
|
50148
|
+
} else if (agent === "sumi") {
|
|
50149
|
+
if ((config2.plugin?.length ?? 0) > 0 || (config2.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical6(configPath) && source.path !== canonical6(join25(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
|
|
50150
|
+
unresolved("external or foreign local plugins require review");
|
|
50073
50151
|
} else if (agent === "hermes") {
|
|
50074
|
-
for (const directory of [
|
|
50152
|
+
for (const directory of [join25(home, ".hermes/plugins"), join25(home, ".hermes/hermes-agent")]) {
|
|
50075
50153
|
safe4(directory);
|
|
50076
|
-
if (
|
|
50154
|
+
if (lstatSync18(directory, { throwIfNoEntry: false }))
|
|
50077
50155
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
50078
50156
|
}
|
|
50079
50157
|
if (Bun.which("hermes") || Object.keys(config2.plugins ?? {}).length)
|
|
@@ -50081,24 +50159,24 @@ function resolveAgentDiscovery(options) {
|
|
|
50081
50159
|
} else if (agent === "gemini") {
|
|
50082
50160
|
if (Object.keys(config2.extensions ?? {}).length || config2.skills?.paths?.length)
|
|
50083
50161
|
unresolved("custom extension or skill paths");
|
|
50084
|
-
const directory =
|
|
50162
|
+
const directory = join25(home, ".gemini/extensions");
|
|
50085
50163
|
safe4(directory);
|
|
50086
|
-
if (
|
|
50164
|
+
if (lstatSync18(directory, { throwIfNoEntry: false }))
|
|
50087
50165
|
for (const name of readdirSync7(directory)) {
|
|
50088
|
-
const root =
|
|
50166
|
+
const root = join25(directory, name);
|
|
50089
50167
|
safe4(root);
|
|
50090
|
-
if (!
|
|
50168
|
+
if (!lstatSync18(root)?.isDirectory())
|
|
50091
50169
|
continue;
|
|
50092
|
-
const raw = witness(
|
|
50170
|
+
const raw = witness(join25(root, "gemini-extension.json"));
|
|
50093
50171
|
if (raw === null)
|
|
50094
50172
|
unresolved("extension registration missing");
|
|
50095
|
-
const manifest = parseConfig(raw,
|
|
50096
|
-
if (manifest.hooks !== undefined || witness(
|
|
50173
|
+
const manifest = parseConfig(raw, join25(root, "gemini-extension.json"));
|
|
50174
|
+
if (manifest.hooks !== undefined || witness(join25(root, "hooks/hooks.json")) !== null || witness(join25(root, ".gemini-extension-install.json")) !== null)
|
|
50097
50175
|
unresolved("extension hooks or linked registration require review");
|
|
50098
|
-
roots.add(
|
|
50176
|
+
roots.add(join25(root, "skills"));
|
|
50099
50177
|
}
|
|
50100
50178
|
}
|
|
50101
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([
|
|
50179
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join25(home, ".hermes/plugins"), join25(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
|
|
50102
50180
|
}
|
|
50103
50181
|
var digest = (text2) => createHash16("sha256").update(text2).digest("hex");
|
|
50104
50182
|
var init_agent_discovery = __esm(() => {
|
|
@@ -50114,16 +50192,17 @@ var init_agent_discovery = __esm(() => {
|
|
|
50114
50192
|
init_codex_hook_discovery_recovery();
|
|
50115
50193
|
init_codex_settings_witness();
|
|
50116
50194
|
init_codex_plugin_skill_controls();
|
|
50195
|
+
init_agent_sumi();
|
|
50117
50196
|
init_native_discovery_roots();
|
|
50118
50197
|
init_agent_discovery_directories();
|
|
50119
50198
|
});
|
|
50120
50199
|
|
|
50121
50200
|
// src/lib/authoring-path.ts
|
|
50122
|
-
import { lstatSync as
|
|
50201
|
+
import { lstatSync as lstatSync19, realpathSync as realpathSync6 } from "fs";
|
|
50123
50202
|
import { homedir as homedir3 } from "os";
|
|
50124
|
-
import { basename as basename9, dirname as dirname16, join as
|
|
50203
|
+
import { basename as basename9, dirname as dirname16, join as join26, resolve as resolve16, sep as sep6 } from "path";
|
|
50125
50204
|
function pathParts(path) {
|
|
50126
|
-
return
|
|
50205
|
+
return resolve16(path).split(sep6).filter(Boolean);
|
|
50127
50206
|
}
|
|
50128
50207
|
function nativeRootMatch(path) {
|
|
50129
50208
|
const parts = pathParts(path);
|
|
@@ -50137,24 +50216,24 @@ function nativeRootMatch(path) {
|
|
|
50137
50216
|
return;
|
|
50138
50217
|
}
|
|
50139
50218
|
function physicalPath(path) {
|
|
50140
|
-
let cursor =
|
|
50219
|
+
let cursor = resolve16(path);
|
|
50141
50220
|
const suffix = [];
|
|
50142
|
-
while (!
|
|
50221
|
+
while (!lstatSync19(cursor, { throwIfNoEntry: false })) {
|
|
50143
50222
|
suffix.unshift(basename9(cursor));
|
|
50144
50223
|
const parent = dirname16(cursor);
|
|
50145
50224
|
if (parent === cursor)
|
|
50146
|
-
return
|
|
50225
|
+
return resolve16(path);
|
|
50147
50226
|
cursor = parent;
|
|
50148
50227
|
}
|
|
50149
|
-
return
|
|
50228
|
+
return resolve16(realpathSync6(cursor), ...suffix);
|
|
50150
50229
|
}
|
|
50151
50230
|
function contains(root, path) {
|
|
50152
50231
|
return path === root || path.startsWith(root + sep6);
|
|
50153
50232
|
}
|
|
50154
50233
|
function configuredRoots(home, explicitHome) {
|
|
50155
|
-
const homeData =
|
|
50234
|
+
const homeData = join26(home, ".hasna", "skills");
|
|
50156
50235
|
const homePolicy = readManagedSkillPolicySnapshot(homeData);
|
|
50157
|
-
const configuredPolicy = !explicitHome &&
|
|
50236
|
+
const configuredPolicy = !explicitHome && resolve16(getDataDirReadOnly()) !== resolve16(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
|
|
50158
50237
|
const policy = homePolicy ?? configuredPolicy;
|
|
50159
50238
|
const bridge = policy?.value.bridge;
|
|
50160
50239
|
if (bridge && (typeof bridge.home !== "string" || physicalPath(bridge.home) !== physicalPath(home))) {
|
|
@@ -50183,8 +50262,8 @@ function configuredRoots(home, explicitHome) {
|
|
|
50183
50262
|
admitBinding(binding);
|
|
50184
50263
|
continue;
|
|
50185
50264
|
}
|
|
50186
|
-
const nativeHome =
|
|
50187
|
-
if (!
|
|
50265
|
+
const nativeHome = join26(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
|
|
50266
|
+
if (!lstatSync19(nativeHome, { throwIfNoEntry: false }))
|
|
50188
50267
|
continue;
|
|
50189
50268
|
roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
|
|
50190
50269
|
}
|
|
@@ -50193,22 +50272,22 @@ function configuredRoots(home, explicitHome) {
|
|
|
50193
50272
|
function assertPortableAuthoringPath(path, options = {}) {
|
|
50194
50273
|
if (typeof path !== "string" || !path || path.includes("\x00"))
|
|
50195
50274
|
throw new Error("Invalid portable authoring path");
|
|
50196
|
-
const lexical =
|
|
50275
|
+
const lexical = resolve16(path);
|
|
50197
50276
|
const physical = physicalPath(lexical);
|
|
50198
50277
|
const candidates = [lexical, physical];
|
|
50199
50278
|
let native = candidates.map(nativeRootMatch).find(Boolean);
|
|
50200
|
-
const home =
|
|
50201
|
-
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) =>
|
|
50202
|
-
defaults.push(
|
|
50279
|
+
const home = resolve16(options.homeDir ?? homedir3());
|
|
50280
|
+
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join26(home, ...parts));
|
|
50281
|
+
defaults.push(join26(home, ".codex/plugins/cache"), join26(home, ".claude/plugins/cache"), join26(home, ".claude/plugins/synced"), join26(home, ".gemini/extensions"));
|
|
50203
50282
|
for (const root of defaults) {
|
|
50204
|
-
if (candidates.some((candidate) => contains(
|
|
50283
|
+
if (candidates.some((candidate) => contains(resolve16(root), candidate) || contains(physicalPath(root), candidate)))
|
|
50205
50284
|
native ??= root;
|
|
50206
50285
|
}
|
|
50207
50286
|
if (native) {
|
|
50208
50287
|
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.`);
|
|
50209
50288
|
}
|
|
50210
50289
|
for (const root of configuredRoots(home, options.homeDir !== undefined)) {
|
|
50211
|
-
if (candidates.some((candidate) => contains(
|
|
50290
|
+
if (candidates.some((candidate) => contains(resolve16(root), candidate) || contains(physicalPath(root), candidate))) {
|
|
50212
50291
|
throw new Error(`Refusing portable Skills authoring below configured native discovery root: ${lexical}`);
|
|
50213
50292
|
}
|
|
50214
50293
|
}
|
|
@@ -50225,32 +50304,32 @@ var init_authoring_path = __esm(() => {
|
|
|
50225
50304
|
|
|
50226
50305
|
// src/lib/portable-skills.ts
|
|
50227
50306
|
import {
|
|
50228
|
-
existsSync as
|
|
50307
|
+
existsSync as existsSync12,
|
|
50229
50308
|
mkdirSync as mkdirSync7,
|
|
50230
50309
|
mkdtempSync,
|
|
50231
50310
|
readdirSync as readdirSync8,
|
|
50232
|
-
realpathSync as
|
|
50311
|
+
realpathSync as realpathSync7,
|
|
50233
50312
|
renameSync as renameSync3,
|
|
50234
50313
|
rmSync as rmSync3,
|
|
50235
50314
|
statSync as statSync7,
|
|
50236
50315
|
writeFileSync as writeFileSync6
|
|
50237
50316
|
} from "fs";
|
|
50238
|
-
import { basename as basename10, dirname as dirname17, isAbsolute as isAbsolute14, join as
|
|
50317
|
+
import { basename as basename10, dirname as dirname17, isAbsolute as isAbsolute14, join as join27, normalize as normalize3, relative as relative5, resolve as resolve17, sep as sep7 } from "path";
|
|
50239
50318
|
function getPortableSkillsRoot(options = {}) {
|
|
50240
50319
|
return resolvePortableSkillsRoot(options, true);
|
|
50241
50320
|
}
|
|
50242
50321
|
function resolvePortableSkillsRoot(options, migrate) {
|
|
50243
50322
|
if (options.rootDir)
|
|
50244
50323
|
return options.rootDir;
|
|
50245
|
-
const appDir = options.homeDir ?
|
|
50246
|
-
const cache =
|
|
50324
|
+
const appDir = options.homeDir ? join27(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
|
|
50325
|
+
const cache = join27(appDir, SKILLS_CACHE_DIRNAME);
|
|
50247
50326
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
|
|
50248
50327
|
return cache;
|
|
50249
|
-
const installed =
|
|
50328
|
+
const installed = join27(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
50250
50329
|
return installed;
|
|
50251
50330
|
}
|
|
50252
50331
|
function getPortableSkillPath(name, options = {}) {
|
|
50253
|
-
return
|
|
50332
|
+
return join27(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
50254
50333
|
}
|
|
50255
50334
|
function findPortableSkill(name, options = {}) {
|
|
50256
50335
|
let normalized;
|
|
@@ -50260,7 +50339,7 @@ function findPortableSkill(name, options = {}) {
|
|
|
50260
50339
|
return null;
|
|
50261
50340
|
}
|
|
50262
50341
|
const path = getPortableSkillPath(normalized, options);
|
|
50263
|
-
if (!
|
|
50342
|
+
if (!existsSync12(path) || !statSync7(path).isDirectory())
|
|
50264
50343
|
return null;
|
|
50265
50344
|
try {
|
|
50266
50345
|
return summarizePortableSkill(path, normalized);
|
|
@@ -50276,7 +50355,7 @@ function listPortableSkills(options = {}) {
|
|
|
50276
50355
|
for (const entry of readdirSync8(root).sort()) {
|
|
50277
50356
|
if (entry.startsWith("."))
|
|
50278
50357
|
continue;
|
|
50279
|
-
const path =
|
|
50358
|
+
const path = join27(root, entry);
|
|
50280
50359
|
if (!safeIsDirectory(path))
|
|
50281
50360
|
continue;
|
|
50282
50361
|
try {
|
|
@@ -50309,11 +50388,11 @@ function isOfficialSkillName(name) {
|
|
|
50309
50388
|
function scaffoldPortableSkill(name, options = {}) {
|
|
50310
50389
|
const skillName = normalizeNewPortableSkillName(name);
|
|
50311
50390
|
const readOnlyRoot = resolvePortableSkillsRoot(options, false);
|
|
50312
|
-
assertPortableAuthoringPath(
|
|
50391
|
+
assertPortableAuthoringPath(join27(readOnlyRoot, skillName), options);
|
|
50313
50392
|
const root = getPortableSkillsRoot(options);
|
|
50314
|
-
const skillPath =
|
|
50393
|
+
const skillPath = join27(root, skillName);
|
|
50315
50394
|
assertPortableAuthoringPath(skillPath, options);
|
|
50316
|
-
if (
|
|
50395
|
+
if (existsSync12(skillPath)) {
|
|
50317
50396
|
if (!options.overwrite)
|
|
50318
50397
|
throw new Error(`Skill '${skillName}' already exists at ${skillPath}`);
|
|
50319
50398
|
rmSync3(skillPath, { recursive: true, force: true });
|
|
@@ -50330,16 +50409,16 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
50330
50409
|
return { name: skillName, path: skillPath, manifest, created: true };
|
|
50331
50410
|
}
|
|
50332
50411
|
function physicalImportPath(path) {
|
|
50333
|
-
let ancestor =
|
|
50412
|
+
let ancestor = resolve17(path);
|
|
50334
50413
|
const suffix = [];
|
|
50335
|
-
while (!
|
|
50414
|
+
while (!existsSync12(ancestor)) {
|
|
50336
50415
|
suffix.unshift(basename10(ancestor));
|
|
50337
50416
|
ancestor = dirname17(ancestor);
|
|
50338
50417
|
}
|
|
50339
|
-
return
|
|
50418
|
+
return join27(realpathSync7(ancestor), ...suffix);
|
|
50340
50419
|
}
|
|
50341
50420
|
function assertDisjointImportPaths(source, destination) {
|
|
50342
|
-
const sourcePath =
|
|
50421
|
+
const sourcePath = realpathSync7(source);
|
|
50343
50422
|
const destinationPath = physicalImportPath(destination);
|
|
50344
50423
|
const contains2 = (parent, child) => {
|
|
50345
50424
|
const path = relative5(parent, child);
|
|
@@ -50351,7 +50430,7 @@ function assertDisjointImportPaths(source, destination) {
|
|
|
50351
50430
|
}
|
|
50352
50431
|
function portPortableSkill(sourcePath, options = {}) {
|
|
50353
50432
|
const absoluteSource = normalize3(sourcePath);
|
|
50354
|
-
if (!
|
|
50433
|
+
if (!existsSync12(absoluteSource) || !statSync7(absoluteSource).isDirectory()) {
|
|
50355
50434
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
50356
50435
|
}
|
|
50357
50436
|
const inferred = readPortableSkillManifestForImport(absoluteSource);
|
|
@@ -50362,14 +50441,14 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
50362
50441
|
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.`;
|
|
50363
50442
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
50364
50443
|
}
|
|
50365
|
-
const readOnlyDestination =
|
|
50444
|
+
const readOnlyDestination = join27(resolvePortableSkillsRoot(options, false), skillName);
|
|
50366
50445
|
assertPortableAuthoringPath(readOnlyDestination, options);
|
|
50367
50446
|
assertDisjointImportPaths(absoluteSource, readOnlyDestination);
|
|
50368
50447
|
const root = getPortableSkillsRoot(options);
|
|
50369
|
-
const destination =
|
|
50448
|
+
const destination = join27(root, skillName);
|
|
50370
50449
|
assertPortableAuthoringPath(destination, options);
|
|
50371
50450
|
assertDisjointImportPaths(absoluteSource, destination);
|
|
50372
|
-
if (
|
|
50451
|
+
if (existsSync12(destination)) {
|
|
50373
50452
|
if (!options.overwrite)
|
|
50374
50453
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
50375
50454
|
rmSync3(destination, { recursive: true, force: true });
|
|
@@ -50397,10 +50476,10 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
50397
50476
|
const issues = [...base.issues];
|
|
50398
50477
|
const warnings = [...base.warnings];
|
|
50399
50478
|
let manifest;
|
|
50400
|
-
if (
|
|
50401
|
-
const skillJsonPath =
|
|
50402
|
-
const skillMdPath =
|
|
50403
|
-
if (!
|
|
50479
|
+
if (existsSync12(skillPath)) {
|
|
50480
|
+
const skillJsonPath = join27(skillPath, "skill.json");
|
|
50481
|
+
const skillMdPath = join27(skillPath, "SKILL.md");
|
|
50482
|
+
if (!existsSync12(skillJsonPath) && !existsSync12(skillMdPath)) {
|
|
50404
50483
|
add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
50405
50484
|
}
|
|
50406
50485
|
try {
|
|
@@ -50419,7 +50498,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
50419
50498
|
add3(issues, "portable.version_missing", "Portable manifest missing version");
|
|
50420
50499
|
}
|
|
50421
50500
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
50422
|
-
strict:
|
|
50501
|
+
strict: existsSync12(join27(skillPath, "skill.json")),
|
|
50423
50502
|
skillPath
|
|
50424
50503
|
});
|
|
50425
50504
|
for (const issue2 of contractIssues)
|
|
@@ -50459,8 +50538,8 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
50459
50538
|
add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
50460
50539
|
continue;
|
|
50461
50540
|
}
|
|
50462
|
-
const entryPath =
|
|
50463
|
-
if (!
|
|
50541
|
+
const entryPath = join27(skillPath, command.entry);
|
|
50542
|
+
if (!existsSync12(entryPath))
|
|
50464
50543
|
add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
50465
50544
|
else if (statSync7(entryPath).isDirectory())
|
|
50466
50545
|
add3(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
|
|
@@ -50470,7 +50549,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
50470
50549
|
} catch (error61) {
|
|
50471
50550
|
add3(issues, "portable.manifest_invalid", error61.message);
|
|
50472
50551
|
}
|
|
50473
|
-
if (manifest?.kind !== "instruction" && !
|
|
50552
|
+
if (manifest?.kind !== "instruction" && !existsSync12(join27(skillPath, "AGENTS.md"))) {
|
|
50474
50553
|
add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
50475
50554
|
}
|
|
50476
50555
|
}
|
|
@@ -50697,8 +50776,8 @@ var init_search = __esm(() => {
|
|
|
50697
50776
|
});
|
|
50698
50777
|
|
|
50699
50778
|
// src/lib/registry.ts
|
|
50700
|
-
import { existsSync as
|
|
50701
|
-
import { join as
|
|
50779
|
+
import { existsSync as existsSync13, readFileSync as readFileSync16, readdirSync as readdirSync9 } from "fs";
|
|
50780
|
+
import { join as join28 } from "path";
|
|
50702
50781
|
function parseSkillMdFrontmatter(content) {
|
|
50703
50782
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
50704
50783
|
if (!match)
|
|
@@ -50731,7 +50810,7 @@ function parseSkillMdFrontmatter(content) {
|
|
|
50731
50810
|
return Object.keys(result).length > 0 ? result : null;
|
|
50732
50811
|
}
|
|
50733
50812
|
function discoverSkillsInDir(dir, source = "custom") {
|
|
50734
|
-
if (!
|
|
50813
|
+
if (!existsSync13(dir))
|
|
50735
50814
|
return [];
|
|
50736
50815
|
const result = [];
|
|
50737
50816
|
try {
|
|
@@ -50739,8 +50818,8 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
50739
50818
|
for (const entry of entries) {
|
|
50740
50819
|
if (!entry.isDirectory())
|
|
50741
50820
|
continue;
|
|
50742
|
-
const skillMdPath =
|
|
50743
|
-
if (!
|
|
50821
|
+
const skillMdPath = join28(dir, entry.name, "SKILL.md");
|
|
50822
|
+
if (!existsSync13(skillMdPath))
|
|
50744
50823
|
continue;
|
|
50745
50824
|
let content;
|
|
50746
50825
|
try {
|
|
@@ -50759,7 +50838,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
50759
50838
|
category: fm.category || "Development Tools",
|
|
50760
50839
|
tags: fm.tags || [],
|
|
50761
50840
|
...fm.kind ? { kind: fm.kind } : {},
|
|
50762
|
-
...isHostedMetadataSkillDir(
|
|
50841
|
+
...isHostedMetadataSkillDir(join28(dir, entry.name)) ? { serverOwned: true } : {},
|
|
50763
50842
|
source
|
|
50764
50843
|
});
|
|
50765
50844
|
}
|
|
@@ -50768,16 +50847,16 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
50768
50847
|
}
|
|
50769
50848
|
function findExtensionSkillPath(name) {
|
|
50770
50849
|
const config2 = loadConfig();
|
|
50771
|
-
if (!config2.extensionsDir || !
|
|
50850
|
+
if (!config2.extensionsDir || !existsSync13(config2.extensionsDir))
|
|
50772
50851
|
return null;
|
|
50773
50852
|
try {
|
|
50774
50853
|
const entries = readdirSync9(config2.extensionsDir, { withFileTypes: true });
|
|
50775
50854
|
for (const entry of entries) {
|
|
50776
50855
|
if (!entry.isDirectory())
|
|
50777
50856
|
continue;
|
|
50778
|
-
const skillDir =
|
|
50779
|
-
const skillMdPath =
|
|
50780
|
-
if (!
|
|
50857
|
+
const skillDir = join28(config2.extensionsDir, entry.name);
|
|
50858
|
+
const skillMdPath = join28(skillDir, "SKILL.md");
|
|
50859
|
+
if (!existsSync13(skillMdPath))
|
|
50781
50860
|
continue;
|
|
50782
50861
|
let content;
|
|
50783
50862
|
try {
|
|
@@ -50820,8 +50899,8 @@ function clearRegistryCache() {
|
|
|
50820
50899
|
registryCacheTime = 0;
|
|
50821
50900
|
registryCacheKey = null;
|
|
50822
50901
|
}
|
|
50823
|
-
function getSkillsByCategory(category) {
|
|
50824
|
-
return loadRegistry().filter((s) => s.category === category);
|
|
50902
|
+
function getSkillsByCategory(category, catalog) {
|
|
50903
|
+
return (catalog ?? loadRegistry()).filter((s) => s.category === category);
|
|
50825
50904
|
}
|
|
50826
50905
|
function getSkill(name) {
|
|
50827
50906
|
const registry2 = loadRegistry();
|
|
@@ -51973,14 +52052,14 @@ var init_remote_workspace_leave = __esm(() => {
|
|
|
51973
52052
|
});
|
|
51974
52053
|
|
|
51975
52054
|
// src/lib/auth-store.ts
|
|
51976
|
-
import { chmodSync, existsSync as
|
|
51977
|
-
import { basename as basename11, dirname as dirname18, join as
|
|
52055
|
+
import { chmodSync, existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync17, renameSync as renameSync4, statSync as statSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
52056
|
+
import { basename as basename11, dirname as dirname18, join as join29 } from "path";
|
|
51978
52057
|
function getAuthFilePath(env = process.env) {
|
|
51979
52058
|
return skillsCredentialFilePath(env);
|
|
51980
52059
|
}
|
|
51981
52060
|
function getIdentityFilePath(env = process.env) {
|
|
51982
52061
|
const file2 = skillsCredentialFilePath(env);
|
|
51983
|
-
return
|
|
52062
|
+
return join29(dirname18(file2), basename11(file2).replace(/^credentials/, "identity") + ".json");
|
|
51984
52063
|
}
|
|
51985
52064
|
function getApiUrl(action, env = process.env, options = {}) {
|
|
51986
52065
|
return requireSkillsApiOrigin(action, env, options);
|
|
@@ -52208,10 +52287,10 @@ async function readQuoteUnavailableCode(response) {
|
|
|
52208
52287
|
let timer;
|
|
52209
52288
|
let deadlineExceeded = false;
|
|
52210
52289
|
const expired = Symbol("quote body deadline");
|
|
52211
|
-
const deadline = new Promise((
|
|
52290
|
+
const deadline = new Promise((resolve18) => {
|
|
52212
52291
|
timer = setTimeout(() => {
|
|
52213
52292
|
deadlineExceeded = true;
|
|
52214
|
-
|
|
52293
|
+
resolve18(expired);
|
|
52215
52294
|
reader.cancel().catch(() => {});
|
|
52216
52295
|
}, 1500);
|
|
52217
52296
|
});
|
|
@@ -53694,12 +53773,12 @@ class RemotePrivatePublicationsClient {
|
|
|
53694
53773
|
previous = view;
|
|
53695
53774
|
if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
|
|
53696
53775
|
return view;
|
|
53697
|
-
await new Promise((
|
|
53776
|
+
await new Promise((resolve18) => {
|
|
53698
53777
|
const timer = setTimeout(done, Math.min(1000, until - Date.now()));
|
|
53699
53778
|
function done() {
|
|
53700
53779
|
clearTimeout(timer);
|
|
53701
53780
|
options.signal?.removeEventListener("abort", done);
|
|
53702
|
-
|
|
53781
|
+
resolve18();
|
|
53703
53782
|
}
|
|
53704
53783
|
options.signal?.addEventListener("abort", done, { once: true });
|
|
53705
53784
|
});
|
|
@@ -53987,10 +54066,10 @@ var init_remote_auth = __esm(() => {
|
|
|
53987
54066
|
});
|
|
53988
54067
|
|
|
53989
54068
|
// src/lib/workspace-profile.ts
|
|
53990
|
-
import { constants as constants11, closeSync as closeSync14, fstatSync as fstatSync14, lstatSync as
|
|
54069
|
+
import { constants as constants11, closeSync as closeSync14, fstatSync as fstatSync14, lstatSync as lstatSync20, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync2, openSync as openSync14, readFileSync as readFileSync18, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
53991
54070
|
function stat2(path) {
|
|
53992
54071
|
try {
|
|
53993
|
-
return
|
|
54072
|
+
return lstatSync20(path);
|
|
53994
54073
|
} catch (error61) {
|
|
53995
54074
|
if (error61.code === "ENOENT")
|
|
53996
54075
|
return null;
|
|
@@ -54219,8 +54298,8 @@ var init_recurring_customer = __esm(() => {
|
|
|
54219
54298
|
});
|
|
54220
54299
|
|
|
54221
54300
|
// src/lib/recurring-recovery.ts
|
|
54222
|
-
import { constants as constants12, closeSync as closeSync15, fsyncSync as fsyncSync4, fstatSync as fstatSync15, lstatSync as
|
|
54223
|
-
import { dirname as dirname19, isAbsolute as isAbsolute15, join as
|
|
54301
|
+
import { constants as constants12, closeSync as closeSync15, fsyncSync as fsyncSync4, fstatSync as fstatSync15, lstatSync as lstatSync21, mkdirSync as mkdirSync10, openSync as openSync15, readSync as readSync10, realpathSync as realpathSync8, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync9 } from "fs";
|
|
54302
|
+
import { dirname as dirname19, isAbsolute as isAbsolute15, join as join30, resolve as resolve18 } from "path";
|
|
54224
54303
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
54225
54304
|
|
|
54226
54305
|
class RecoveryOwner {
|
|
@@ -54228,10 +54307,10 @@ class RecoveryOwner {
|
|
|
54228
54307
|
parents = [];
|
|
54229
54308
|
constructor(directory) {
|
|
54230
54309
|
this.directory = directory;
|
|
54231
|
-
if (!isAbsolute15(directory) ||
|
|
54310
|
+
if (!isAbsolute15(directory) || resolve18(directory) !== directory || realpathSync8(directory) !== directory)
|
|
54232
54311
|
invalid5();
|
|
54233
54312
|
for (let path = directory;; path = dirname19(path)) {
|
|
54234
|
-
const stat3 =
|
|
54313
|
+
const stat3 = lstatSync21(path);
|
|
54235
54314
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
54236
54315
|
invalid5();
|
|
54237
54316
|
this.parents.push({ path, dev: stat3.dev, ino: stat3.ino });
|
|
@@ -54241,20 +54320,20 @@ class RecoveryOwner {
|
|
|
54241
54320
|
this.assert();
|
|
54242
54321
|
}
|
|
54243
54322
|
assert() {
|
|
54244
|
-
if (
|
|
54323
|
+
if (realpathSync8(this.directory) !== this.directory)
|
|
54245
54324
|
invalid5();
|
|
54246
54325
|
for (const prior of this.parents) {
|
|
54247
|
-
const now =
|
|
54326
|
+
const now = lstatSync21(prior.path);
|
|
54248
54327
|
if (!now.isDirectory() || now.isSymbolicLink() || now.dev !== prior.dev || now.ino !== prior.ino)
|
|
54249
54328
|
invalid5();
|
|
54250
54329
|
}
|
|
54251
|
-
const own2 =
|
|
54330
|
+
const own2 = lstatSync21(this.directory);
|
|
54252
54331
|
if ((own2.mode & 511) !== 448 || (own2.mode & 3584) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
54253
54332
|
invalid5();
|
|
54254
54333
|
}
|
|
54255
54334
|
read(name) {
|
|
54256
54335
|
this.assert();
|
|
54257
|
-
const fd = openSync15(
|
|
54336
|
+
const fd = openSync15(join30(this.directory, name), constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
54258
54337
|
try {
|
|
54259
54338
|
const before = fstatSync15(fd);
|
|
54260
54339
|
if (!before.isFile() || before.nlink !== 1 || (before.mode & 4095) !== 384 || before.size < 1 || before.size > 8192 || process.getuid && before.uid !== process.getuid())
|
|
@@ -54267,7 +54346,7 @@ class RecoveryOwner {
|
|
|
54267
54346
|
break;
|
|
54268
54347
|
size += n2;
|
|
54269
54348
|
}
|
|
54270
|
-
const after = fstatSync15(fd), path =
|
|
54349
|
+
const after = fstatSync15(fd), path = lstatSync21(join30(this.directory, name));
|
|
54271
54350
|
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())
|
|
54272
54351
|
invalid5();
|
|
54273
54352
|
this.assert();
|
|
@@ -54280,7 +54359,7 @@ class RecoveryOwner {
|
|
|
54280
54359
|
this.assert();
|
|
54281
54360
|
const bytes = canonicalJson2(value, 8192) + `
|
|
54282
54361
|
`;
|
|
54283
|
-
const fd = openSync15(
|
|
54362
|
+
const fd = openSync15(join30(this.directory, name), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
|
|
54284
54363
|
try {
|
|
54285
54364
|
writeFileSync9(fd, bytes);
|
|
54286
54365
|
fsyncSync4(fd);
|
|
@@ -54307,14 +54386,14 @@ class RecoveryOwner {
|
|
|
54307
54386
|
if (this.read("state.json") !== expected)
|
|
54308
54387
|
invalid5();
|
|
54309
54388
|
this.assert();
|
|
54310
|
-
renameSync6(
|
|
54389
|
+
renameSync6(join30(this.directory, name), join30(this.directory, "state.json"));
|
|
54311
54390
|
this.sync();
|
|
54312
54391
|
}
|
|
54313
54392
|
async locked(action) {
|
|
54314
54393
|
this.assert();
|
|
54315
54394
|
let fd;
|
|
54316
54395
|
try {
|
|
54317
|
-
fd = openSync15(
|
|
54396
|
+
fd = openSync15(join30(this.directory, "operation.lock"), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
|
|
54318
54397
|
} catch {
|
|
54319
54398
|
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.");
|
|
54320
54399
|
}
|
|
@@ -54327,10 +54406,10 @@ class RecoveryOwner {
|
|
|
54327
54406
|
} finally {
|
|
54328
54407
|
closeSync15(fd);
|
|
54329
54408
|
this.assert();
|
|
54330
|
-
const now =
|
|
54409
|
+
const now = lstatSync21(join30(this.directory, "operation.lock"));
|
|
54331
54410
|
if (owner2.dev !== now.dev || owner2.ino !== now.ino || !now.isFile() || now.isSymbolicLink())
|
|
54332
54411
|
invalid5();
|
|
54333
|
-
unlinkSync5(
|
|
54412
|
+
unlinkSync5(join30(this.directory, "operation.lock"));
|
|
54334
54413
|
this.sync();
|
|
54335
54414
|
}
|
|
54336
54415
|
}
|
|
@@ -54363,7 +54442,7 @@ function base(customer, organizationId) {
|
|
|
54363
54442
|
};
|
|
54364
54443
|
}
|
|
54365
54444
|
function create(directory, intent) {
|
|
54366
|
-
if (!isAbsolute15(directory) ||
|
|
54445
|
+
if (!isAbsolute15(directory) || resolve18(directory) !== directory || realpathSync8(dirname19(directory)) !== dirname19(directory))
|
|
54367
54446
|
invalid5();
|
|
54368
54447
|
mkdirSync10(directory, { mode: 448 });
|
|
54369
54448
|
const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -56461,20 +56540,20 @@ var init_credential_state = __esm(() => {
|
|
|
56461
56540
|
|
|
56462
56541
|
// src/lib/run-state.ts
|
|
56463
56542
|
import { createHash as createHash19, randomBytes } from "crypto";
|
|
56464
|
-
import { existsSync as
|
|
56465
|
-
import { extname, join as
|
|
56543
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync19, readdirSync as readdirSync10, statSync as statSync9, writeFileSync as writeFileSync10 } from "fs";
|
|
56544
|
+
import { extname, join as join31, relative as relative6 } from "path";
|
|
56466
56545
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
56467
56546
|
const now = new Date;
|
|
56468
56547
|
const id = createRunId(now);
|
|
56469
56548
|
const day = now.toISOString().slice(0, 10);
|
|
56470
56549
|
const skillName = normalizeSkillName(params.skill);
|
|
56471
56550
|
const root = getProjectStateDir(targetDir);
|
|
56472
|
-
const runDir =
|
|
56473
|
-
const logsDir =
|
|
56474
|
-
const exportDir =
|
|
56551
|
+
const runDir = join31(root, "runs", day, id);
|
|
56552
|
+
const logsDir = join31(runDir, "logs");
|
|
56553
|
+
const exportDir = join31(root, "exports", skillName, id);
|
|
56475
56554
|
mkdirSync11(logsDir, { recursive: true });
|
|
56476
56555
|
mkdirSync11(exportDir, { recursive: true });
|
|
56477
|
-
mkdirSync11(
|
|
56556
|
+
mkdirSync11(join31(root, "tmp"), { recursive: true });
|
|
56478
56557
|
const record11 = {
|
|
56479
56558
|
id,
|
|
56480
56559
|
skill: skillName,
|
|
@@ -56526,22 +56605,22 @@ function updateSkillRun(context2, patch) {
|
|
|
56526
56605
|
return context2.record;
|
|
56527
56606
|
}
|
|
56528
56607
|
function writeRunLogs(context2, stdout = "", stderr = "") {
|
|
56529
|
-
writeFileSync10(
|
|
56530
|
-
writeFileSync10(
|
|
56608
|
+
writeFileSync10(join31(context2.logsDir, "stdout.log"), stdout);
|
|
56609
|
+
writeFileSync10(join31(context2.logsDir, "stderr.log"), stderr);
|
|
56531
56610
|
}
|
|
56532
56611
|
function appendRunEvent(context2, event, data = {}) {
|
|
56533
56612
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
56534
56613
|
`;
|
|
56535
|
-
const path =
|
|
56536
|
-
const previous =
|
|
56614
|
+
const path = join31(context2.runDir, "events.ndjson");
|
|
56615
|
+
const previous = existsSync15(path) ? readFileSync19(path, "utf-8") : "";
|
|
56537
56616
|
writeFileSync10(path, previous + line);
|
|
56538
56617
|
}
|
|
56539
56618
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
56540
|
-
const runsRoot =
|
|
56541
|
-
if (!
|
|
56619
|
+
const runsRoot = join31(getProjectStateDir(targetDir), "runs");
|
|
56620
|
+
if (!existsSync15(runsRoot))
|
|
56542
56621
|
return null;
|
|
56543
56622
|
for (const day of readdirSync10(runsRoot)) {
|
|
56544
|
-
const record11 = readRunRecord(
|
|
56623
|
+
const record11 = readRunRecord(join31(runsRoot, day, runId));
|
|
56545
56624
|
if (record11)
|
|
56546
56625
|
return record11;
|
|
56547
56626
|
}
|
|
@@ -56558,15 +56637,15 @@ function skillRunEnv(context2) {
|
|
|
56558
56637
|
};
|
|
56559
56638
|
}
|
|
56560
56639
|
function writeRunRecord(context2) {
|
|
56561
|
-
writeFileSync10(
|
|
56640
|
+
writeFileSync10(join31(context2.runDir, "run.json"), JSON.stringify(context2.record, null, 2) + `
|
|
56562
56641
|
`);
|
|
56563
56642
|
}
|
|
56564
56643
|
function writeArtifactsManifest(context2, artifacts) {
|
|
56565
|
-
writeFileSync10(
|
|
56644
|
+
writeFileSync10(join31(context2.runDir, "artifacts.json"), JSON.stringify({ runId: context2.record.id, artifacts }, null, 2) + `
|
|
56566
56645
|
`);
|
|
56567
56646
|
}
|
|
56568
56647
|
function collectRunArtifacts(context2) {
|
|
56569
|
-
if (!
|
|
56648
|
+
if (!existsSync15(context2.exportDir))
|
|
56570
56649
|
return [];
|
|
56571
56650
|
const artifacts = [];
|
|
56572
56651
|
for (const path of walkFiles(context2.exportDir)) {
|
|
@@ -56582,8 +56661,8 @@ function collectRunArtifacts(context2) {
|
|
|
56582
56661
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
56583
56662
|
}
|
|
56584
56663
|
function readRunRecord(runDir) {
|
|
56585
|
-
const path =
|
|
56586
|
-
if (!
|
|
56664
|
+
const path = join31(runDir, "run.json");
|
|
56665
|
+
if (!existsSync15(path))
|
|
56587
56666
|
return null;
|
|
56588
56667
|
try {
|
|
56589
56668
|
return JSON.parse(readFileSync19(path, "utf-8"));
|
|
@@ -56594,7 +56673,7 @@ function readRunRecord(runDir) {
|
|
|
56594
56673
|
function walkFiles(dir) {
|
|
56595
56674
|
const files = [];
|
|
56596
56675
|
for (const entry of readdirSync10(dir)) {
|
|
56597
|
-
const full =
|
|
56676
|
+
const full = join31(dir, entry);
|
|
56598
56677
|
if (statSync9(full).isDirectory())
|
|
56599
56678
|
files.push(...walkFiles(full));
|
|
56600
56679
|
else
|
|
@@ -56851,7 +56930,7 @@ import { closeSync as closeSync16, fstatSync as fstatSync16, openSync as openSyn
|
|
|
56851
56930
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
56852
56931
|
import { createRequire as createRequire2 } from "module";
|
|
56853
56932
|
import { hostname as osHostname2 } from "os";
|
|
56854
|
-
import { isAbsolute as isAbsolute17, join as
|
|
56933
|
+
import { isAbsolute as isAbsolute17, join as join32 } from "path";
|
|
56855
56934
|
import { createRequire as createRequire22 } from "module";
|
|
56856
56935
|
function envToken2(name) {
|
|
56857
56936
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -56882,14 +56961,14 @@ function hasnaHomeDir2(env) {
|
|
|
56882
56961
|
if (override)
|
|
56883
56962
|
return override;
|
|
56884
56963
|
const home = homeDir2(env);
|
|
56885
|
-
return home ?
|
|
56964
|
+
return home ? join32(home, HASNA_HOME_DIR2) : null;
|
|
56886
56965
|
}
|
|
56887
56966
|
function appConfigDir2(name, env) {
|
|
56888
56967
|
const configRoot = absoluteOverride2(env, HASNA_CONFIG_HOME_ENV_KEY2);
|
|
56889
56968
|
if (configRoot)
|
|
56890
|
-
return
|
|
56969
|
+
return join32(configRoot, name);
|
|
56891
56970
|
const root = hasnaHomeDir2(env);
|
|
56892
|
-
return root ?
|
|
56971
|
+
return root ? join32(root, name, CONFIG_SUBDIR2) : null;
|
|
56893
56972
|
}
|
|
56894
56973
|
function credentialDiskSourceList2(name, env, profile = null) {
|
|
56895
56974
|
if (!SAFE_APP_SLUG2.test(name))
|
|
@@ -56898,7 +56977,7 @@ function credentialDiskSourceList2(name, env, profile = null) {
|
|
|
56898
56977
|
if (!directory2)
|
|
56899
56978
|
return [];
|
|
56900
56979
|
const file2 = profile ? `${CREDENTIALS_FILE2}-${profile}` : CREDENTIALS_FILE2;
|
|
56901
|
-
return [{ path:
|
|
56980
|
+
return [{ path: join32(directory2, file2), tier: "disk" }];
|
|
56902
56981
|
}
|
|
56903
56982
|
function credentialDiskSources2(name, env) {
|
|
56904
56983
|
return credentialDiskSourceList2(name, env, null).map((s) => s.path);
|
|
@@ -58012,7 +58091,7 @@ function createSecretsClientFromEnv(env = process.env, overrides = {}) {
|
|
|
58012
58091
|
});
|
|
58013
58092
|
return new SecretsClient({ ...clientOverrides, baseUrl, apiKey });
|
|
58014
58093
|
}
|
|
58015
|
-
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((
|
|
58094
|
+
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((resolve19) => setTimeout(resolve19, 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;
|
|
58016
58095
|
var init_sdk = __esm(() => {
|
|
58017
58096
|
init_transport2 = __esm2(() => {
|
|
58018
58097
|
CredentialResolutionError2 = class CredentialResolutionError3 extends Error {
|
|
@@ -58147,7 +58226,7 @@ var init_sdk = __esm(() => {
|
|
|
58147
58226
|
});
|
|
58148
58227
|
|
|
58149
58228
|
// src/lib/execution-secrets.ts
|
|
58150
|
-
import { constants as constants13, closeSync as closeSync17, fstatSync as fstatSync17, openSync as openSync17, readSync as readSync11, realpathSync as
|
|
58229
|
+
import { constants as constants13, closeSync as closeSync17, fstatSync as fstatSync17, openSync as openSync17, readSync as readSync11, realpathSync as realpathSync9 } from "fs";
|
|
58151
58230
|
import { hostname as stationHostname } from "os";
|
|
58152
58231
|
function selectedSecretBindingsTemplate(scope, names, createClient = createSecretsClientFromEnv) {
|
|
58153
58232
|
let secretsAuthority;
|
|
@@ -58160,7 +58239,7 @@ function selectedSecretBindingsTemplate(scope, names, createClient = createSecre
|
|
|
58160
58239
|
return {
|
|
58161
58240
|
schema: "hasna.skills-secret-bindings.v1",
|
|
58162
58241
|
selection: { authority, workspaceId, profileId: scope.profileId, profileRevision, slug: slug2, version: version2, bundleDigest },
|
|
58163
|
-
consumer: { stationId: process.env.HASNA_STATION || stationHostname(), workspaceDirectory:
|
|
58242
|
+
consumer: { stationId: process.env.HASNA_STATION || stationHostname(), workspaceDirectory: realpathSync9(scope.cwd) },
|
|
58164
58243
|
secretsAuthority,
|
|
58165
58244
|
bindings: Object.fromEntries(names.map((name) => [name, ""]))
|
|
58166
58245
|
};
|
|
@@ -58198,7 +58277,7 @@ function validateSelectedSecretBindings(value, scope, names) {
|
|
|
58198
58277
|
}
|
|
58199
58278
|
let workspaceDirectory;
|
|
58200
58279
|
try {
|
|
58201
|
-
workspaceDirectory =
|
|
58280
|
+
workspaceDirectory = realpathSync9(scope.cwd);
|
|
58202
58281
|
} catch {
|
|
58203
58282
|
return refuse2("SECRET_BINDING_CONSUMER_MISMATCH", "The execution workspace cannot be resolved.");
|
|
58204
58283
|
}
|
|
@@ -58391,8 +58470,8 @@ __export(exports_selected_run, {
|
|
|
58391
58470
|
});
|
|
58392
58471
|
import { createHash as createHash20 } from "crypto";
|
|
58393
58472
|
import { spawn } from "child_process";
|
|
58394
|
-
import { mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync11, realpathSync as
|
|
58395
|
-
import { dirname as dirname20, join as
|
|
58473
|
+
import { mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync11, realpathSync as realpathSync10 } from "fs";
|
|
58474
|
+
import { dirname as dirname20, join as join33, resolve as resolve19 } from "path";
|
|
58396
58475
|
import { tmpdir, hostname as stationHostname2 } from "os";
|
|
58397
58476
|
async function resolveSelectedRun(spec, profileId, options = {}) {
|
|
58398
58477
|
const context2 = await resolveSelectionContext(profileId, options);
|
|
@@ -58472,7 +58551,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
58472
58551
|
throw new SkillSelectionError("INVALID_SECRET_BINDINGS", "Explicit environment values must be bounded strings without NUL bytes.");
|
|
58473
58552
|
secretEnv[name] = value;
|
|
58474
58553
|
}
|
|
58475
|
-
const runDirectory = mkdtempSync3(
|
|
58554
|
+
const runDirectory = mkdtempSync3(join33(tmpdir(), "skills-execution-"));
|
|
58476
58555
|
const paths = new SkillEntryPaths;
|
|
58477
58556
|
for (const entry of entries) {
|
|
58478
58557
|
paths.add(entry.path, 100, () => {
|
|
@@ -58480,12 +58559,12 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
58480
58559
|
}, () => {
|
|
58481
58560
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
58482
58561
|
});
|
|
58483
|
-
const destination =
|
|
58562
|
+
const destination = join33(runDirectory, entry.path);
|
|
58484
58563
|
mkdirSync12(dirname20(destination), { recursive: true, mode: 448 });
|
|
58485
58564
|
writeFileSync11(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
58486
58565
|
}
|
|
58487
58566
|
env.SKILLS_INPUT_JSON = input2;
|
|
58488
|
-
env.SKILLS_WORKSPACE_DIR =
|
|
58567
|
+
env.SKILLS_WORKSPACE_DIR = resolve19(options.cwd ?? process.cwd());
|
|
58489
58568
|
env.SKILLS_RUN_DIR = runDirectory;
|
|
58490
58569
|
if (runtime.version) {
|
|
58491
58570
|
const version2 = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], "--version"], runDirectory, env, "", Math.min(timeoutMs, 5000));
|
|
@@ -58498,7 +58577,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
58498
58577
|
const { authority: authority2, workspaceId, profileRevision, slug: slug2, version: version2, bundleDigest } = selection2;
|
|
58499
58578
|
const request2 = {
|
|
58500
58579
|
selection: { authority: authority2, workspaceId, profileId, profileRevision, slug: slug2, version: version2, bundleDigest },
|
|
58501
|
-
consumer: { stationId: process.env.HASNA_STATION || stationHostname2(), workspaceDirectory:
|
|
58580
|
+
consumer: { stationId: process.env.HASNA_STATION || stationHostname2(), workspaceDirectory: realpathSync10(options.cwd ?? process.cwd()) }
|
|
58502
58581
|
};
|
|
58503
58582
|
const grant = await (options.resolveExecutionGrant ?? resolveExecutionGrant)(request2);
|
|
58504
58583
|
if (!grant || !grantIdentifier(grant.policyRevision) || !grantIdentifier(grant.grantId))
|
|
@@ -58508,7 +58587,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
58508
58587
|
}
|
|
58509
58588
|
if (bindings)
|
|
58510
58589
|
secretEnv = await resolveSelectedSecrets(bindings, options.createSecretsClient);
|
|
58511
|
-
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [],
|
|
58590
|
+
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], join33(runDirectory, declaredEntry), ...args], runDirectory, { ...env, ...secretEnv }, input2, timeoutMs);
|
|
58512
58591
|
result.stdout = redactExecutionSecrets(result.stdout, secretEnv);
|
|
58513
58592
|
result.stderr = redactExecutionSecrets(result.stderr, secretEnv);
|
|
58514
58593
|
const receipt = {
|
|
@@ -58521,7 +58600,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
58521
58600
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
58522
58601
|
...result
|
|
58523
58602
|
};
|
|
58524
|
-
writeFileSync11(
|
|
58603
|
+
writeFileSync11(join33(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
|
|
58525
58604
|
return receipt;
|
|
58526
58605
|
}
|
|
58527
58606
|
async function subprocess(command, cwd, env, input2, timeoutMs) {
|
|
@@ -58710,8 +58789,8 @@ var init_blog_article = __esm(() => {
|
|
|
58710
58789
|
});
|
|
58711
58790
|
|
|
58712
58791
|
// src/mcp/operation-tools.ts
|
|
58713
|
-
import { existsSync as
|
|
58714
|
-
import { join as
|
|
58792
|
+
import { existsSync as existsSync16, readdirSync as readdirSync11, statSync as statSync10 } from "fs";
|
|
58793
|
+
import { join as join34 } from "path";
|
|
58715
58794
|
function registerOperationTools(server) {
|
|
58716
58795
|
server.registerTool("cloud_skill_eligibility", {
|
|
58717
58796
|
title: "Cloud Skill Eligibility",
|
|
@@ -59183,12 +59262,12 @@ function registerOperationTools(server) {
|
|
|
59183
59262
|
const agents = [];
|
|
59184
59263
|
for (const agent of AGENT_TARGETS) {
|
|
59185
59264
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
59186
|
-
const exists =
|
|
59265
|
+
const exists = existsSync16(agentSkillsPath);
|
|
59187
59266
|
let skillCount = 0;
|
|
59188
59267
|
if (exists) {
|
|
59189
59268
|
try {
|
|
59190
59269
|
skillCount = readdirSync11(agentSkillsPath).filter((f) => {
|
|
59191
|
-
const full =
|
|
59270
|
+
const full = join34(agentSkillsPath, f);
|
|
59192
59271
|
return !f.startsWith(".") && statSync10(full).isDirectory();
|
|
59193
59272
|
}).length;
|
|
59194
59273
|
} catch {}
|
|
@@ -59255,16 +59334,16 @@ var init_operation_tools = __esm(() => {
|
|
|
59255
59334
|
});
|
|
59256
59335
|
|
|
59257
59336
|
// src/lib/feedback.ts
|
|
59258
|
-
import { appendFileSync, existsSync as
|
|
59259
|
-
import { dirname as dirname21, join as
|
|
59337
|
+
import { appendFileSync, existsSync as existsSync17, mkdirSync as mkdirSync13 } from "fs";
|
|
59338
|
+
import { dirname as dirname21, join as join35 } from "path";
|
|
59260
59339
|
import { Database } from "bun:sqlite";
|
|
59261
59340
|
function getFeedbackDbPath() {
|
|
59262
|
-
return
|
|
59341
|
+
return join35(getDataDir(), "skills.db");
|
|
59263
59342
|
}
|
|
59264
59343
|
function getFeedbackDb() {
|
|
59265
59344
|
const dbPath = getFeedbackDbPath();
|
|
59266
59345
|
const dir = dirname21(dbPath);
|
|
59267
|
-
if (!
|
|
59346
|
+
if (!existsSync17(dir))
|
|
59268
59347
|
mkdirSync13(dir, { recursive: true });
|
|
59269
59348
|
const db = new Database(dbPath);
|
|
59270
59349
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -59291,9 +59370,9 @@ function saveFeedback(input2) {
|
|
|
59291
59370
|
throw new Error("Feedback message is required");
|
|
59292
59371
|
const category = input2.category ?? "general";
|
|
59293
59372
|
if (isApiMode()) {
|
|
59294
|
-
const path =
|
|
59373
|
+
const path = join35(getDataDir(), "feedback.jsonl");
|
|
59295
59374
|
const dir = dirname21(path);
|
|
59296
|
-
if (!
|
|
59375
|
+
if (!existsSync17(dir))
|
|
59297
59376
|
mkdirSync13(dir, { recursive: true });
|
|
59298
59377
|
appendFileSync(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
|
|
59299
59378
|
`);
|
|
@@ -59455,14 +59534,14 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
59455
59534
|
});
|
|
59456
59535
|
|
|
59457
59536
|
// src/lib/scheduler.ts
|
|
59458
|
-
import { existsSync as
|
|
59459
|
-
import { join as
|
|
59537
|
+
import { existsSync as existsSync18, readFileSync as readFileSync21, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "fs";
|
|
59538
|
+
import { join as join36 } from "path";
|
|
59460
59539
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
59461
|
-
return
|
|
59540
|
+
return join36(targetDir, ".skills", "schedules.json");
|
|
59462
59541
|
}
|
|
59463
59542
|
function loadSchedules(targetDir = process.cwd()) {
|
|
59464
59543
|
const path = getSchedulesPath(targetDir);
|
|
59465
|
-
if (
|
|
59544
|
+
if (existsSync18(path)) {
|
|
59466
59545
|
try {
|
|
59467
59546
|
return JSON.parse(readFileSync21(path, "utf-8"));
|
|
59468
59547
|
} catch {}
|
|
@@ -59471,8 +59550,8 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
59471
59550
|
}
|
|
59472
59551
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
59473
59552
|
const path = getSchedulesPath(targetDir);
|
|
59474
|
-
const dir =
|
|
59475
|
-
if (!
|
|
59553
|
+
const dir = join36(targetDir, ".skills");
|
|
59554
|
+
if (!existsSync18(dir))
|
|
59476
59555
|
mkdirSync14(dir, { recursive: true });
|
|
59477
59556
|
writeFileSync12(path, JSON.stringify(data, null, 2));
|
|
59478
59557
|
}
|
|
@@ -59745,14 +59824,14 @@ var init_schedule_tools = __esm(() => {
|
|
|
59745
59824
|
// src/lib/native-storage.ts
|
|
59746
59825
|
import { createHash as createHash21, createHmac } from "crypto";
|
|
59747
59826
|
import {
|
|
59748
|
-
existsSync as
|
|
59827
|
+
existsSync as existsSync19,
|
|
59749
59828
|
mkdirSync as mkdirSync15,
|
|
59750
59829
|
readFileSync as readFileSync22,
|
|
59751
59830
|
readdirSync as readdirSync12,
|
|
59752
59831
|
statSync as statSync11,
|
|
59753
59832
|
writeFileSync as writeFileSync13
|
|
59754
59833
|
} from "fs";
|
|
59755
|
-
import { dirname as dirname22, join as
|
|
59834
|
+
import { dirname as dirname22, join as join37, normalize as normalize4, relative as relative7, sep as sep8 } from "path";
|
|
59756
59835
|
function resolveSkillsNativeStorageConfig(env = process.env) {
|
|
59757
59836
|
assertNoRetiredModeEnvVars(env, {
|
|
59758
59837
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -59793,7 +59872,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
59793
59872
|
local: {
|
|
59794
59873
|
dataDir: getDataDir(),
|
|
59795
59874
|
projectStateDir: getProjectStateDir(targetDir),
|
|
59796
|
-
feedbackDbPath:
|
|
59875
|
+
feedbackDbPath: join37(getDataDir(), "skills.db")
|
|
59797
59876
|
},
|
|
59798
59877
|
remote: {
|
|
59799
59878
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -59813,7 +59892,7 @@ function getStorageStatus(options = {}) {
|
|
|
59813
59892
|
function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
59814
59893
|
const projectStateDir = getProjectStateDir(targetDir);
|
|
59815
59894
|
const files = [];
|
|
59816
|
-
if (
|
|
59895
|
+
if (existsSync19(projectStateDir)) {
|
|
59817
59896
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
59818
59897
|
const bytes = readFileSync22(filePath);
|
|
59819
59898
|
const relativePath = toPosix(relative7(targetDir, filePath));
|
|
@@ -59874,7 +59953,7 @@ function parsePositiveInteger(value) {
|
|
|
59874
59953
|
function walkFiles2(dir) {
|
|
59875
59954
|
const files = [];
|
|
59876
59955
|
for (const entry of readdirSync12(dir)) {
|
|
59877
|
-
const full =
|
|
59956
|
+
const full = join37(dir, entry);
|
|
59878
59957
|
const stats = statSync11(full);
|
|
59879
59958
|
if (stats.isDirectory())
|
|
59880
59959
|
files.push(...walkFiles2(full));
|
|
@@ -60112,20 +60191,20 @@ var init_private_publication_customer = __esm(() => {
|
|
|
60112
60191
|
});
|
|
60113
60192
|
|
|
60114
60193
|
// src/lib/private-publication-recovery.ts
|
|
60115
|
-
import { constants as constants14, closeSync as closeSync18, fsyncSync as fsyncSync5, fstatSync as fstatSync18, lstatSync as
|
|
60116
|
-
import { dirname as dirname23, isAbsolute as isAbsolute18, join as
|
|
60194
|
+
import { constants as constants14, closeSync as closeSync18, fsyncSync as fsyncSync5, fstatSync as fstatSync18, lstatSync as lstatSync22, mkdirSync as mkdirSync16, openSync as openSync18, readSync as readSync12, realpathSync as realpathSync11, renameSync as renameSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
|
|
60195
|
+
import { dirname as dirname23, isAbsolute as isAbsolute18, join as join38, resolve as resolve20 } from "path";
|
|
60117
60196
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
60118
60197
|
function safeDirectory(directory2) {
|
|
60119
|
-
if (!isAbsolute18(directory2) || directory2 !==
|
|
60198
|
+
if (!isAbsolute18(directory2) || directory2 !== resolve20(directory2) || realpathSync11(directory2) !== directory2)
|
|
60120
60199
|
return fail2();
|
|
60121
60200
|
for (let path = directory2;; path = dirname23(path)) {
|
|
60122
|
-
const stat3 =
|
|
60201
|
+
const stat3 = lstatSync22(path);
|
|
60123
60202
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
60124
60203
|
return fail2();
|
|
60125
60204
|
if (path === dirname23(path))
|
|
60126
60205
|
break;
|
|
60127
60206
|
}
|
|
60128
|
-
const own2 =
|
|
60207
|
+
const own2 = lstatSync22(directory2);
|
|
60129
60208
|
if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
60130
60209
|
return fail2();
|
|
60131
60210
|
return { dev: own2.dev, ino: own2.ino };
|
|
@@ -60136,7 +60215,7 @@ function unchangedDirectory(directory2, identity3) {
|
|
|
60136
60215
|
return fail2();
|
|
60137
60216
|
}
|
|
60138
60217
|
function readOwned(directory2, name, max) {
|
|
60139
|
-
const identity3 = safeDirectory(directory2), file2 =
|
|
60218
|
+
const identity3 = safeDirectory(directory2), file2 = join38(directory2, name);
|
|
60140
60219
|
const fd = openSync18(file2, constants14.O_RDONLY | constants14.O_NOFOLLOW);
|
|
60141
60220
|
try {
|
|
60142
60221
|
const stat3 = fstatSync18(fd);
|
|
@@ -60160,7 +60239,7 @@ function readOwned(directory2, name, max) {
|
|
|
60160
60239
|
}
|
|
60161
60240
|
}
|
|
60162
60241
|
function writeOwned(directory2, name, bytes) {
|
|
60163
|
-
const fd = openSync18(
|
|
60242
|
+
const fd = openSync18(join38(directory2, name), constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
|
|
60164
60243
|
try {
|
|
60165
60244
|
writeFileSync14(fd, bytes);
|
|
60166
60245
|
fsyncSync5(fd);
|
|
@@ -60173,7 +60252,7 @@ function save(directory2, value) {
|
|
|
60173
60252
|
writeOwned(directory2, temporary, JSON.stringify(value) + `
|
|
60174
60253
|
`);
|
|
60175
60254
|
unchangedDirectory(directory2, identity3);
|
|
60176
|
-
renameSync7(
|
|
60255
|
+
renameSync7(join38(directory2, temporary), join38(directory2, "receipt.json"));
|
|
60177
60256
|
const fd = openSync18(directory2, constants14.O_RDONLY | constants14.O_NOFOLLOW);
|
|
60178
60257
|
try {
|
|
60179
60258
|
fsyncSync5(fd);
|
|
@@ -60186,7 +60265,7 @@ function bind(client, receipt) {
|
|
|
60186
60265
|
throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
|
|
60187
60266
|
}
|
|
60188
60267
|
async function locked(directory2, action) {
|
|
60189
|
-
const identity3 = safeDirectory(directory2), file2 =
|
|
60268
|
+
const identity3 = safeDirectory(directory2), file2 = join38(directory2, "operation.lock");
|
|
60190
60269
|
let fd;
|
|
60191
60270
|
try {
|
|
60192
60271
|
fd = openSync18(file2, constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
|
|
@@ -60202,7 +60281,7 @@ async function locked(directory2, action) {
|
|
|
60202
60281
|
} finally {
|
|
60203
60282
|
closeSync18(fd);
|
|
60204
60283
|
unchangedDirectory(directory2, identity3);
|
|
60205
|
-
const now =
|
|
60284
|
+
const now = lstatSync22(file2);
|
|
60206
60285
|
if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
|
|
60207
60286
|
fail2();
|
|
60208
60287
|
unlinkSync6(file2);
|
|
@@ -60254,7 +60333,7 @@ async function preparePrivatePublication(client, sourceDirectory, recoveryDirect
|
|
|
60254
60333
|
phase: "prepared",
|
|
60255
60334
|
intent: null
|
|
60256
60335
|
};
|
|
60257
|
-
if (!isAbsolute18(recoveryDirectory) ||
|
|
60336
|
+
if (!isAbsolute18(recoveryDirectory) || resolve20(recoveryDirectory) !== recoveryDirectory || realpathSync11(dirname23(recoveryDirectory)) !== dirname23(recoveryDirectory))
|
|
60258
60337
|
return fail2();
|
|
60259
60338
|
mkdirSync16(recoveryDirectory, { mode: 448 });
|
|
60260
60339
|
safeDirectory(recoveryDirectory);
|
|
@@ -61070,7 +61149,7 @@ var RequestError, nonJoinedHeaders, validHeaderName, isHttpWhitespace = (code2)
|
|
|
61070
61149
|
request2[bodyBufferKey] = buffered;
|
|
61071
61150
|
return Promise.resolve(buffered);
|
|
61072
61151
|
}
|
|
61073
|
-
const promise3 = new Promise((
|
|
61152
|
+
const promise3 = new Promise((resolve21, reject) => {
|
|
61074
61153
|
const chunks = [];
|
|
61075
61154
|
let settled = false;
|
|
61076
61155
|
const finish = (callback) => {
|
|
@@ -61092,7 +61171,7 @@ var RequestError, nonJoinedHeaders, validHeaderName, isHttpWhitespace = (code2)
|
|
|
61092
61171
|
reject(error61 ?? normalizeAbortError(request2, incoming));
|
|
61093
61172
|
else {
|
|
61094
61173
|
request2[bodyBufferKey] = recovered;
|
|
61095
|
-
|
|
61174
|
+
resolve21(recovered);
|
|
61096
61175
|
}
|
|
61097
61176
|
});
|
|
61098
61177
|
return true;
|
|
@@ -61104,7 +61183,7 @@ var RequestError, nonJoinedHeaders, validHeaderName, isHttpWhitespace = (code2)
|
|
|
61104
61183
|
finish(() => {
|
|
61105
61184
|
const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks);
|
|
61106
61185
|
request2[bodyBufferKey] = buffer;
|
|
61107
|
-
|
|
61186
|
+
resolve21(buffer);
|
|
61108
61187
|
});
|
|
61109
61188
|
};
|
|
61110
61189
|
const onError = (error61) => {
|
|
@@ -61378,7 +61457,7 @@ var RequestError, nonJoinedHeaders, validHeaderName, isHttpWhitespace = (code2)
|
|
|
61378
61457
|
});
|
|
61379
61458
|
if (!chunk) {
|
|
61380
61459
|
if (i === 1) {
|
|
61381
|
-
await new Promise((
|
|
61460
|
+
await new Promise((resolve21) => setTimeout(resolve21));
|
|
61382
61461
|
maxReadCount = 3;
|
|
61383
61462
|
continue;
|
|
61384
61463
|
}
|
|
@@ -62608,9 +62687,9 @@ data:
|
|
|
62608
62687
|
const initRequest = messages.find((m) => isInitializeRequest(m));
|
|
62609
62688
|
const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
|
|
62610
62689
|
if (this._enableJsonResponse) {
|
|
62611
|
-
return new Promise((
|
|
62690
|
+
return new Promise((resolve21) => {
|
|
62612
62691
|
this._streamMapping.set(streamId, {
|
|
62613
|
-
resolveJson:
|
|
62692
|
+
resolveJson: resolve21,
|
|
62614
62693
|
cleanup: () => {
|
|
62615
62694
|
this._streamMapping.delete(streamId);
|
|
62616
62695
|
}
|
|
@@ -62979,19 +63058,19 @@ async function connectMcpForNode() {
|
|
|
62979
63058
|
return { server: server2, transport };
|
|
62980
63059
|
}
|
|
62981
63060
|
function readBody(req) {
|
|
62982
|
-
return new Promise((
|
|
63061
|
+
return new Promise((resolve21, reject) => {
|
|
62983
63062
|
const chunks = [];
|
|
62984
63063
|
req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
62985
63064
|
req.on("end", () => {
|
|
62986
63065
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
62987
63066
|
if (!raw.trim()) {
|
|
62988
|
-
|
|
63067
|
+
resolve21(undefined);
|
|
62989
63068
|
return;
|
|
62990
63069
|
}
|
|
62991
63070
|
try {
|
|
62992
|
-
|
|
63071
|
+
resolve21(JSON.parse(raw));
|
|
62993
63072
|
} catch {
|
|
62994
|
-
|
|
63073
|
+
resolve21(undefined);
|
|
62995
63074
|
}
|
|
62996
63075
|
});
|
|
62997
63076
|
req.on("error", reject);
|
|
@@ -63033,9 +63112,9 @@ async function startSkillsMcpHttpServer(options = {}) {
|
|
|
63033
63112
|
}
|
|
63034
63113
|
}
|
|
63035
63114
|
});
|
|
63036
|
-
await new Promise((
|
|
63115
|
+
await new Promise((resolve21, reject) => {
|
|
63037
63116
|
httpServer.once("error", reject);
|
|
63038
|
-
httpServer.listen(port, hostname4, () =>
|
|
63117
|
+
httpServer.listen(port, hostname4, () => resolve21());
|
|
63039
63118
|
});
|
|
63040
63119
|
const address = httpServer.address();
|
|
63041
63120
|
const listenPort = typeof address === "object" && address ? address.port : port;
|