@hasna/skills 0.10.28 → 0.10.31

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/dist/index.js CHANGED
@@ -6988,8 +6988,8 @@ var require_public_api = __commonJS((exports) => {
6988
6988
  });
6989
6989
 
6990
6990
  // src/lib/registry.ts
6991
- import { existsSync as existsSync14, readFileSync as readFileSync18, readdirSync as readdirSync12 } from "fs";
6992
- import { join as join30 } from "path";
6991
+ import { existsSync as existsSync15, readFileSync as readFileSync18, readdirSync as readdirSync12 } from "fs";
6992
+ import { join as join31 } from "path";
6993
6993
 
6994
6994
  // src/lib/config.ts
6995
6995
  import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync } from "fs";
@@ -7252,17 +7252,17 @@ function unsetConfig(key, scope = "project") {
7252
7252
 
7253
7253
  // src/lib/portable-skills.ts
7254
7254
  import {
7255
- existsSync as existsSync13,
7255
+ existsSync as existsSync14,
7256
7256
  mkdirSync as mkdirSync9,
7257
7257
  mkdtempSync as mkdtempSync2,
7258
7258
  readdirSync as readdirSync11,
7259
- realpathSync as realpathSync9,
7259
+ realpathSync as realpathSync10,
7260
7260
  renameSync as renameSync5,
7261
7261
  rmSync as rmSync4,
7262
7262
  statSync as statSync10,
7263
7263
  writeFileSync as writeFileSync8
7264
7264
  } from "fs";
7265
- import { basename as basename11, dirname as dirname19, isAbsolute as isAbsolute17, join as join29, normalize as normalize4, relative as relative6, resolve as resolve17, sep as sep8 } from "path";
7265
+ import { basename as basename11, dirname as dirname19, isAbsolute as isAbsolute17, join as join30, normalize as normalize4, relative as relative6, resolve as resolve18, sep as sep8 } from "path";
7266
7266
 
7267
7267
  // src/lib/registry-data/index.ts
7268
7268
  var SKILLS = [];
@@ -8904,6 +8904,8 @@ var NATIVE_SKILL_ROOTS = [
8904
8904
  ["codex", ".codex/skills"],
8905
8905
  ["codex", ".agents/skills"],
8906
8906
  ["gemini", ".gemini/skills"],
8907
+ ["sumi", ".sumi/skills"],
8908
+ ["sumi", ".sumi/skill"],
8907
8909
  ["codewith", ".codewith/skills"],
8908
8910
  ["opencode", ".config/opencode/skills"],
8909
8911
  ["opencode", ".opencode/skills"],
@@ -8918,12 +8920,12 @@ var NATIVE_SKILL_ROOTS = [
8918
8920
  ];
8919
8921
 
8920
8922
  // src/lib/authoring-path.ts
8921
- import { lstatSync as lstatSync22, realpathSync as realpathSync8 } from "fs";
8923
+ import { lstatSync as lstatSync23, realpathSync as realpathSync9 } from "fs";
8922
8924
  import { homedir as homedir6 } from "os";
8923
- import { basename as basename10, dirname as dirname18, join as join28, resolve as resolve16, sep as sep7 } from "path";
8925
+ import { basename as basename10, dirname as dirname18, join as join29, resolve as resolve17, sep as sep7 } from "path";
8924
8926
 
8925
8927
  // src/lib/agent-adapters.ts
8926
- var INTEGRATION_AGENTS = ["claude", "codex", "gemini", "opencode", "cursor", "hermes"];
8928
+ var INTEGRATION_AGENTS = ["claude", "codex", "gemini", "opencode", "cursor", "hermes", "sumi"];
8927
8929
  function renderAgentHookCommand(command, agent, profileId, event) {
8928
8930
  if (typeof profileId !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(profileId) || profileId.includes(".."))
8929
8931
  throw new Error("Invalid selection profile id");
@@ -8934,6 +8936,7 @@ var AGENT_ADAPTERS = {
8934
8936
  codex: { root: ".codex/skills", config: ".codex/hooks.json", events: ["UserPromptSubmit", "SessionStart", "SubagentStart"], promptContext: true },
8935
8937
  gemini: { root: ".gemini/skills", config: ".gemini/settings.json", events: ["BeforeAgent", "SessionStart"], promptContext: true },
8936
8938
  opencode: { root: ".config/opencode/skills", config: ".config/opencode/opencode.json", events: ["chat.message"], promptContext: true },
8939
+ sumi: { root: ".hasna-internal/sumi/config/skills", config: ".hasna-internal/sumi/config/sumi.json", events: ["prompt", "context"], promptContext: true },
8937
8940
  hermes: { root: ".hermes/skills", config: ".hermes/config.yaml", events: ["pre_llm_call", "pre_tool_call"], promptContext: true, promptFailureMode: "open", toolFailureMode: "supervised-child-errors-block", requiresNativeTrust: true },
8938
8941
  cursor: { root: ".cursor/skills", config: ".cursor/hooks.json", events: ["beforeSubmitPrompt", "sessionStart"], promptContext: false }
8939
8942
  };
@@ -9139,8 +9142,8 @@ function assertAgentPolicyCollections(policy) {
9139
9142
 
9140
9143
  // src/lib/agent-discovery.ts
9141
9144
  import { createHash as createHash18 } from "crypto";
9142
- import { lstatSync as lstatSync21, readFileSync as readFileSync17, readdirSync as readdirSync10, realpathSync as realpathSync7 } from "fs";
9143
- import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute16, join as join27, resolve as resolve15, sep as sep6 } from "path";
9145
+ import { lstatSync as lstatSync22, readFileSync as readFileSync17, readdirSync as readdirSync10, realpathSync as realpathSync8 } from "fs";
9146
+ import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute16, join as join28, resolve as resolve16, sep as sep6 } from "path";
9144
9147
  import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
9145
9148
 
9146
9149
  // node_modules/yaml/dist/index.js
@@ -9652,12 +9655,12 @@ function hashDiscoveryPathFile(path, budget, changes) {
9652
9655
  }
9653
9656
 
9654
9657
  // src/lib/plugin-discovery.ts
9655
- import { closeSync as closeSync10, constants as constants9, fstatSync as fstatSync10, lstatSync as lstatSync18, openSync as openSync10, opendirSync as opendirSync5, readSync as readSync8 } from "fs";
9656
- import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute14, join as join26, resolve as resolve13 } from "path";
9658
+ import { closeSync as closeSync10, constants as constants9, fstatSync as fstatSync10, lstatSync as lstatSync19, openSync as openSync10, opendirSync as opendirSync5, readSync as readSync8 } from "fs";
9659
+ import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute14, join as join27, resolve as resolve14 } from "path";
9657
9660
 
9658
9661
  // src/lib/plugin-admission.ts
9659
9662
  import { homedir as homedir5 } from "os";
9660
- import { isAbsolute as isAbsolute13, join as join25, resolve as resolve12 } from "path";
9663
+ import { isAbsolute as isAbsolute13, join as join26, resolve as resolve13 } from "path";
9661
9664
 
9662
9665
  // src/lib/selection-cache.ts
9663
9666
  import { createHash as createHash6, randomUUID } from "crypto";
@@ -10914,7 +10917,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
10914
10917
  // package.json
10915
10918
  var package_default = {
10916
10919
  name: "@hasna/skills",
10917
- version: "0.10.28",
10920
+ version: "0.10.31",
10918
10921
  description: "Skills library for AI coding agents",
10919
10922
  type: "module",
10920
10923
  bin: {
@@ -12724,19 +12727,19 @@ async function prepareSkillDependencies(skillPath, env, timeoutMs = DEFAULT_PREP
12724
12727
  }
12725
12728
 
12726
12729
  // src/lib/skillinfo.ts
12727
- import { existsSync as existsSync12, readFileSync as readFileSync16 } from "fs";
12728
- import { join as join21 } from "path";
12730
+ import { existsSync as existsSync13, readFileSync as readFileSync16 } from "fs";
12731
+ import { join as join23 } from "path";
12729
12732
 
12730
12733
  // src/lib/installer.ts
12731
- import { existsSync as existsSync11, readFileSync as readFileSync15, rmSync as rmSync2 } from "fs";
12732
- import { join as join20 } from "path";
12734
+ import { existsSync as existsSync12, readFileSync as readFileSync15, rmSync as rmSync2 } from "fs";
12735
+ import { join as join21 } from "path";
12733
12736
  import { homedir as homedir4 } from "os";
12734
12737
 
12735
12738
  // src/lib/agent-sync.ts
12736
12739
  import {
12737
12740
  cpSync as cpSync2,
12738
- existsSync as existsSync9,
12739
- lstatSync as lstatSync16,
12741
+ existsSync as existsSync10,
12742
+ lstatSync as lstatSync17,
12740
12743
  mkdirSync as mkdirSync6,
12741
12744
  mkdtempSync,
12742
12745
  readFileSync as readFileSync13,
@@ -12747,7 +12750,7 @@ import {
12747
12750
  writeFileSync as writeFileSync5
12748
12751
  } from "fs";
12749
12752
  import { homedir as homedir3 } from "os";
12750
- import { basename as basename6, dirname as dirname12, join as join18 } from "path";
12753
+ import { basename as basename6, dirname as dirname12, join as join19 } from "path";
12751
12754
 
12752
12755
  // src/lib/codex-local-mcp-controls.ts
12753
12756
  function isCodexLocalStdioMcpServer(name, server) {
@@ -13506,6 +13509,29 @@ function mcpControls(path, read2) {
13506
13509
  refuse2();
13507
13510
  return sha2562;
13508
13511
  }
13512
+ function isBundledCleanupHooks(root, namespace, value) {
13513
+ const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
13514
+ const exactKeys = (v, keys) => Object.keys(v).length === keys.length && keys.every((key) => Object.hasOwn(v, key));
13515
+ if (basename5(dirname10(root)) !== namespace || basename5(dirname10(dirname10(root))) !== "openai-bundled")
13516
+ return false;
13517
+ const server = namespace === "unified-computer-use" ? "cua_repl" : ["browser", "chrome", "chrome-dev", "chrome-internal", "computer-use"].includes(namespace) ? "node_repl" : undefined;
13518
+ if (!server || !object5(value) || !exactKeys(value, ["hooks"]) || !object5(value.hooks))
13519
+ return false;
13520
+ const events = Object.entries(value.hooks);
13521
+ if (!events.length || events.length > 3)
13522
+ return false;
13523
+ for (const [event, groups] of events) {
13524
+ if (!["Interrupt", "SubagentStop", "Stop"].includes(event) || !Array.isArray(groups) || groups.length !== 1)
13525
+ return false;
13526
+ const group = groups[0];
13527
+ if (!object5(group) || !exactKeys(group, ["hooks"]) || !Array.isArray(group.hooks) || group.hooks.length !== 1)
13528
+ return false;
13529
+ const handler = group.hooks[0];
13530
+ if (!object5(handler) || !exactKeys(handler, ["type", "server", "tool", "input"]) || handler.type !== "mcp_tool" || handler.server !== server || handler.tool !== "turn_ended" || !object5(handler.input) || !exactKeys(handler.input, ["hook_event_name", "session_id", "turn_id"]) || handler.input.hook_event_name !== "${hook_event_name}" || handler.input.turn_id !== "${turn_id}" || handler.input.session_id !== (event === "SubagentStop" ? "${agent_id}" : "${session_id}"))
13531
+ return false;
13532
+ }
13533
+ return true;
13534
+ }
13509
13535
  function rootControls(root, read2) {
13510
13536
  const manifestPath = join14(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync12(manifestPath, { throwIfNoEntry: false });
13511
13537
  if (!lstatSync12(join14(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
@@ -13523,9 +13549,11 @@ function rootControls(root, read2) {
13523
13549
  const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
13524
13550
  if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
13525
13551
  refuse2();
13526
- if (manifest.hooks !== undefined || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync12(join14(root, "hooks"), { throwIfNoEntry: false }))
13552
+ if (manifest.hooks !== undefined && !isBundledCleanupHooks(root, manifest.name, manifest.hooks) || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync12(join14(root, "hooks"), { throwIfNoEntry: false }))
13527
13553
  refuse2();
13528
13554
  const mcp = join14(root, ".mcp.json"), mcpPresent = lstatSync12(mcp, { throwIfNoEntry: false });
13555
+ if (manifest.hooks !== undefined && (manifest.mcpServers !== undefined || mcpPresent))
13556
+ refuse2();
13529
13557
  if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
13530
13558
  refuse2();
13531
13559
  if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
@@ -14124,8 +14152,8 @@ function upgradeCodexSettingsWitnessV3(previous, reviewedSettingsPath) {
14124
14152
  // src/lib/agent-integration.ts
14125
14153
  import { createHash as createHash12, randomUUID as randomUUID2 } from "crypto";
14126
14154
  import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
14127
- import { existsSync as existsSync8, lstatSync as lstatSync15, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync12, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync6, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync8, closeSync as closeSync8, fsyncSync as fsyncSync2, fstatSync as fstatSync8, readSync as readSync6, constants as constants7, linkSync } from "fs";
14128
- import { dirname as dirname11, join as join17, resolve as resolve10, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
14155
+ import { existsSync as existsSync9, lstatSync as lstatSync16, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync12, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync7, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync8, closeSync as closeSync8, fsyncSync as fsyncSync2, fstatSync as fstatSync8, readSync as readSync6, constants as constants7, linkSync } from "fs";
14156
+ import { dirname as dirname11, join as join18, resolve as resolve11, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
14129
14157
  import { homedir as homedir2 } from "os";
14130
14158
 
14131
14159
  // src/lib/managed-policy.ts
@@ -14519,6 +14547,114 @@ function disableCodexBundledSkills(text2) {
14519
14547
  return [...candidates][0];
14520
14548
  }
14521
14549
 
14550
+ // src/lib/agent-sumi.ts
14551
+ import { existsSync as existsSync8, lstatSync as lstatSync15, realpathSync as realpathSync6 } from "fs";
14552
+ import { join as join17, resolve as resolve10 } from "path";
14553
+ function sumiConfigDirectory(home, env = process.env) {
14554
+ for (const key of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
14555
+ if (env[key] !== undefined)
14556
+ throw new Error(`Sumi ${key} requires a dedicated discovery adapter; unset it before Skills integration`);
14557
+ const selected = (key) => env[key]?.trim() ? env[key] : undefined;
14558
+ const expand = (value) => resolve10(value === "~" ? home : value.startsWith("~/") ? join17(home, value.slice(2)) : value);
14559
+ const explicit = selected("SUMI_CONFIG_DIR");
14560
+ const xdg = selected("XDG_CONFIG_HOME");
14561
+ const custom = selected("SUMI_HOME");
14562
+ const canonical5 = explicit ? expand(explicit) : xdg ? join17(expand(xdg), "sumi") : join17(custom ? expand(custom) : join17(home, ".hasna-internal/sumi"), "config");
14563
+ if (explicit || xdg || custom)
14564
+ return canonical5;
14565
+ const legacy = join17(home, ".config/sumi");
14566
+ const a = lstatSync15(canonical5, { throwIfNoEntry: false }), b = lstatSync15(legacy, { throwIfNoEntry: false });
14567
+ if (a && b && realpathSync6(canonical5) !== realpathSync6(legacy))
14568
+ throw new Error("Sumi config roots conflict; complete native home adoption before Skills integration");
14569
+ const path = a ? canonical5 : b ? legacy : canonical5;
14570
+ if (!existsSync8(path))
14571
+ return path;
14572
+ const physical = realpathSync6(path);
14573
+ if ((a?.isSymbolicLink() || b?.isSymbolicLink()) && ![canonical5, legacy].includes(physical))
14574
+ throw new Error("Sumi config alias must resolve to its canonical or legacy root");
14575
+ return physical;
14576
+ }
14577
+ function sumiBridgeRoot(home) {
14578
+ return join17(sumiConfigDirectory(home), "skills");
14579
+ }
14580
+ function sumiConfigPath(home) {
14581
+ return join17(sumiConfigDirectory(home), "sumi.json");
14582
+ }
14583
+ function renderSumiPlugin(command, profile) {
14584
+ return `// Managed by @hasna/skills. Regenerate with skills hook install --agent sumi.
14585
+ import { spawn } from "node:child_process";
14586
+ const command = ${JSON.stringify(command)};
14587
+ const profile = ${JSON.stringify(profile)};
14588
+ function context(input) {
14589
+ return new Promise((resolve, reject) => {
14590
+ const child = spawn(command, ["hook", "user-prompt", "--agent", "sumi", "--selection-profile", profile], { cwd: input.cwd, stdio: ["pipe", "pipe", "pipe"] });
14591
+ const chunks = []; let bytes = 0, failure;
14592
+ const timer = setTimeout(() => { failure = new Error("Skills prompt hook timed out"); child.kill("SIGKILL"); }, 15000);
14593
+ child.stdout.on("data", chunk => { bytes += chunk.length; if (bytes > 1048576) { failure = new Error("Skills prompt hook output exceeded its limit"); child.kill("SIGKILL"); } else chunks.push(chunk); });
14594
+ child.stderr.on("data", () => {});
14595
+ child.stdin.on("error", () => {});
14596
+ child.on("error", error => { clearTimeout(timer); reject(error); });
14597
+ child.on("close", code => {
14598
+ clearTimeout(timer);
14599
+ if (failure || code !== 0) return reject(failure ?? new Error("Skills prompt hook failed"));
14600
+ try {
14601
+ const result = JSON.parse(Buffer.concat(chunks).toString("utf8"));
14602
+ if (!result || typeof result !== "object" || Array.isArray(result)) throw new Error("Invalid Skills hook response");
14603
+ if (result.decision === "block" || result.continue === false) throw new Error("Skills prompt hook refused");
14604
+ if (Object.keys(result).length && (!result.hookSpecificOutput || result.hookSpecificOutput.hookEventName !== input.hook_event_name)) throw new Error("Invalid Skills hook response");
14605
+ const text = result.hookSpecificOutput?.additionalContext ?? "";
14606
+ if (typeof text !== "string") throw new Error("Invalid Skills prompt context");
14607
+ resolve(text);
14608
+ } catch (error) { reject(error); }
14609
+ });
14610
+ child.stdin.end(JSON.stringify(input));
14611
+ });
14612
+ }
14613
+ export default {
14614
+ id: "local.hasna-skills-cli",
14615
+ async setup(ctx) {
14616
+ if (!ctx?.session?.hook || !ctx?.session?.get || !ctx?.skill?.transform || !ctx?.tool?.hook) throw new Error("Unsupported Sumi native Skills contract");
14617
+ const registrations = [];
14618
+ const sessions = new Set();
14619
+ async function input(sessionID, prompt, first) {
14620
+ // The Promise adapter unwraps single-data endpoint responses.
14621
+ const session = await ctx.session.get({ sessionID });
14622
+ if (!session || session.id !== sessionID || typeof session.location?.directory !== "string" || (session.parentID !== undefined && typeof session.parentID !== "string") || session.parentID === sessionID) throw new Error("Invalid Sumi session custody");
14623
+ return { hook_event_name: first ? session.parentID ? "SubagentStart" : "SessionStart" : "UserPromptSubmit", cwd: session.location.directory, session_id: sessionID, parent_session_id: session.parentID ?? null, prompt, restore: true };
14624
+ }
14625
+ registrations.push(await ctx.skill.transform(editor => {
14626
+ for (const skill of editor.list()) if (skill.id !== "skills-cli" || skill.name !== "skills-cli") editor.remove(skill.id);
14627
+ }));
14628
+ // Native config transforms may add skills after this transform. Guard
14629
+ // both direct tool calls and prompt attachments at the consumption edge.
14630
+ registrations.push(await ctx.tool.hook("execute.before", event => {
14631
+ if (event.tool === "skill" && event.input?.id !== "skills-cli") throw new Error("Native Sumi skill payload refused; use Skills CLI");
14632
+ }));
14633
+ registrations.push(await ctx.session.hook("prompt", async event => {
14634
+ if (typeof event.prompt?.text !== "string") throw new Error("Invalid Sumi prompt");
14635
+ if (event.prompt.skills !== undefined && (!Array.isArray(event.prompt.skills) || event.prompt.skills.some(skill => skill?.id !== "skills-cli"))) throw new Error("Native Sumi skill attachment refused; use Skills CLI");
14636
+ await context(await input(event.sessionID, event.prompt.text, !sessions.has(event.sessionID)));
14637
+ sessions.add(event.sessionID);
14638
+ }));
14639
+ registrations.push(await ctx.session.hook("context", async event => {
14640
+ const last = event.messages.findLast(message => message.role === "user");
14641
+ const prompt = (last?.content ?? []).filter(part => part.type === "text").map(part => part.text).join("\\n");
14642
+ // Recheck on every primary request, including resumed and synthetic
14643
+ // sessions. The CLI owns optional failures versus explicit refusals.
14644
+ const text = await context(await input(event.sessionID, prompt, !sessions.has(event.sessionID)));
14645
+ if (text) event.system.push({ type: "text", text });
14646
+ sessions.add(event.sessionID);
14647
+ }));
14648
+ return async () => { for (const registration of registrations) await registration.dispose(); };
14649
+ },
14650
+ };
14651
+ `;
14652
+ }
14653
+ var SUMI_SKILL_PERMISSIONS = [
14654
+ { action: "skill", resource: "*", effect: "deny" },
14655
+ { action: "skill", resource: "skills-cli", effect: "allow" }
14656
+ ];
14657
+
14522
14658
  // src/lib/agent-integration.ts
14523
14659
  var sha3 = (data) => createHash12("sha256").update(data).digest("hex");
14524
14660
  var ROOTS = NATIVE_SKILL_ROOTS;
@@ -14553,11 +14689,11 @@ function isSystemRootAlias(path) {
14553
14689
  const target = `/private${path}`, link = `private${path}`;
14554
14690
  const identity4 = (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}`;
14555
14691
  try {
14556
- const before = lstatSync15(path, { bigint: true });
14692
+ const before = lstatSync16(path, { bigint: true });
14557
14693
  if (!before.isSymbolicLink() || before.uid !== 0n || readlinkSync4(path) !== link)
14558
14694
  return false;
14559
14695
  const directories = ["/", "/private", target].map((directory) => {
14560
- const stat = lstatSync15(directory, { bigint: true });
14696
+ const stat = lstatSync16(directory, { bigint: true });
14561
14697
  if (!stat.isDirectory() || stat.uid !== 0n)
14562
14698
  throw new Error("Untrusted system alias directory");
14563
14699
  if (directory !== "/private/tmp") {
@@ -14574,23 +14710,23 @@ function isSystemRootAlias(path) {
14574
14710
  }
14575
14711
  return { directory, identity: identity4(stat) };
14576
14712
  });
14577
- return realpathSync6(path) === target && readlinkSync4(path) === link && identity4(lstatSync15(path, { bigint: true })) === identity4(before) && directories.every((item) => identity4(lstatSync15(item.directory, { bigint: true })) === item.identity);
14713
+ return realpathSync7(path) === target && readlinkSync4(path) === link && identity4(lstatSync16(path, { bigint: true })) === identity4(before) && directories.every((item) => identity4(lstatSync16(item.directory, { bigint: true })) === item.identity);
14578
14714
  } catch {
14579
14715
  return false;
14580
14716
  }
14581
14717
  }
14582
14718
  function canonicalSystemPath(path) {
14583
- const absolute = resolve10(path), root = `/${absolute.split(sep5)[1]}`;
14584
- if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync15(root, { throwIfNoEntry: false })?.isSymbolicLink())
14719
+ const absolute = resolve11(path), root = `/${absolute.split(sep5)[1]}`;
14720
+ if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync16(root, { throwIfNoEntry: false })?.isSymbolicLink())
14585
14721
  return absolute;
14586
14722
  if (!isSystemRootAlias(root))
14587
14723
  throw new Error(`Refusing symlink path: ${root}`);
14588
14724
  return `/private${absolute}`;
14589
14725
  }
14590
14726
  function assertSafePath(path) {
14591
- let cursor = resolve10(path);
14727
+ let cursor = resolve11(path);
14592
14728
  while (true) {
14593
- if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
14729
+ if (lstatSync16(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
14594
14730
  throw new Error(`Refusing symlink path: ${cursor}`);
14595
14731
  const parent = dirname11(cursor);
14596
14732
  if (parent === cursor)
@@ -14600,16 +14736,16 @@ function assertSafePath(path) {
14600
14736
  }
14601
14737
  function readRootAlias(home, agent) {
14602
14738
  assertSafePath(home);
14603
- const realHome = realpathSync6(home), alias = join17(realHome, `.${agent}`);
14604
- const stat = lstatSync15(alias, { throwIfNoEntry: false, bigint: true });
14739
+ const realHome = realpathSync7(home), alias = join18(realHome, `.${agent}`);
14740
+ const stat = lstatSync16(alias, { throwIfNoEntry: false, bigint: true });
14605
14741
  if (!stat?.isSymbolicLink())
14606
14742
  throw new Error(`Agent root alias changed after planning: ${alias}`);
14607
- const link = readlinkSync4(alias), targetPath = resolve10(dirname11(alias), link);
14743
+ const link = readlinkSync4(alias), targetPath = resolve11(dirname11(alias), link);
14608
14744
  assertSafePath(targetPath);
14609
- const targetStat = lstatSync15(targetPath, { throwIfNoEntry: false });
14745
+ const targetStat = lstatSync16(targetPath, { throwIfNoEntry: false });
14610
14746
  if (!targetStat?.isDirectory())
14611
14747
  throw new Error(`Agent root alias must target an existing directory: ${alias}`);
14612
- const target = realpathSync6(targetPath), inside = relative5(realHome, target);
14748
+ const target = realpathSync7(targetPath), inside = relative5(realHome, target);
14613
14749
  if (!inside || inside === ".." || inside.startsWith(`..${sep5}`) || isAbsolute11(inside))
14614
14750
  throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
14615
14751
  return { agent, home: realHome, alias, target, link, aliasIdentity: `${stat.dev}:${stat.ino}:${stat.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
@@ -14619,7 +14755,7 @@ function rootAliases(home, allowed = false) {
14619
14755
  return [];
14620
14756
  const result = [];
14621
14757
  for (const agent of ["claude", "codex"])
14622
- if (lstatSync15(join17(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
14758
+ if (lstatSync16(join18(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
14623
14759
  result.push(readRootAlias(home, agent));
14624
14760
  if (result.some((item, index) => result.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep5) || other.target.startsWith(item.target + sep5))))
14625
14761
  throw new Error("Agent root alias targets must not overlap");
@@ -14627,7 +14763,7 @@ function rootAliases(home, allowed = false) {
14627
14763
  }
14628
14764
  function canonicalAgentPath(path, aliases) {
14629
14765
  const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
14630
- return binding ? join17(binding.target, relative5(binding.alias, absolute)) : absolute;
14766
+ return binding ? join18(binding.target, relative5(binding.alias, absolute)) : absolute;
14631
14767
  }
14632
14768
  function disabledCodexSkillPaths(config, aliases) {
14633
14769
  const skills = config.skills;
@@ -14646,7 +14782,7 @@ function disabledCodexSkillPaths(config, aliases) {
14646
14782
  continue;
14647
14783
  let document2;
14648
14784
  try {
14649
- document2 = realpathSync6(canonicalAgentPath(entry.path, aliases));
14785
+ document2 = realpathSync7(canonicalAgentPath(entry.path, aliases));
14650
14786
  } catch {
14651
14787
  continue;
14652
14788
  }
@@ -14658,7 +14794,7 @@ function disabledCodexSkillPaths(config, aliases) {
14658
14794
  }
14659
14795
  function recheckRootAliases(aliases) {
14660
14796
  for (const binding of aliases) {
14661
- if (!["claude", "codex"].includes(binding.agent) || binding.alias !== join17(binding.home, `.${binding.agent}`))
14797
+ if (!["claude", "codex"].includes(binding.agent) || binding.alias !== join18(binding.home, `.${binding.agent}`))
14662
14798
  throw new Error("Invalid agent root alias binding");
14663
14799
  const current = readRootAlias(binding.home, binding.agent);
14664
14800
  if (JSON.stringify(current) !== JSON.stringify(binding))
@@ -14667,7 +14803,7 @@ function recheckRootAliases(aliases) {
14667
14803
  }
14668
14804
  function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
14669
14805
  assertSafePath(path);
14670
- const before = lstatSync15(path);
14806
+ const before = lstatSync16(path);
14671
14807
  if (!before.isFile() || before.size > maximum)
14672
14808
  throw new Error("Unsupported or oversized native skill file");
14673
14809
  const descriptor = openSync8(path, constants7.O_RDONLY | constants7.O_NOFOLLOW | constants7.O_NONBLOCK);
@@ -14683,7 +14819,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
14683
14819
  break;
14684
14820
  length += count;
14685
14821
  }
14686
- const after = fstatSync8(descriptor), current = lstatSync15(path);
14822
+ const after = fstatSync8(descriptor), current = lstatSync16(path);
14687
14823
  if (current.dev !== opened.dev || current.ino !== opened.ino || current.size !== after.size || current.mtimeMs !== after.mtimeMs || current.ctimeMs !== after.ctimeMs || length !== before.size || after.size !== before.size || after.mtimeMs !== opened.mtimeMs || after.ctimeMs !== opened.ctimeMs)
14688
14824
  throw new Error("Native skill file changed while reading");
14689
14825
  return bytes.subarray(0, length);
@@ -14695,14 +14831,14 @@ function treeHash(root) {
14695
14831
  const hash2 = createHash12("sha256");
14696
14832
  let bytes = 0, files = 0;
14697
14833
  function visit2(path) {
14698
- const stat = lstatSync15(path);
14834
+ const stat = lstatSync16(path);
14699
14835
  if (stat.isSymbolicLink())
14700
14836
  throw new Error(`Refusing symlink in skill: ${path}`);
14701
14837
  const rel = relative5(root, path);
14702
14838
  if (stat.isDirectory()) {
14703
14839
  hash2.update(`d\x00${rel}\x00`);
14704
14840
  for (const name of readdirSync8(path).sort())
14705
- visit2(join17(path, name));
14841
+ visit2(join18(path, name));
14706
14842
  return;
14707
14843
  }
14708
14844
  if (!stat.isFile())
@@ -14724,10 +14860,10 @@ function selectNativeMigrationTargets(inventory, manifest) {
14724
14860
  const identities = new Set;
14725
14861
  const selected = [];
14726
14862
  for (const target of manifest.targets) {
14727
- if (!isAbsolute11(target.projectRoot) || resolve10(target.projectRoot) !== target.projectRoot)
14863
+ if (!isAbsolute11(target.projectRoot) || resolve11(target.projectRoot) !== target.projectRoot)
14728
14864
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
14729
- const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative5(projectRoot, resolve10(projectRoot, target.path));
14730
- if (!existsSync8(projectRoot) || !lstatSync15(projectRoot).isDirectory())
14865
+ const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative5(projectRoot, resolve11(projectRoot, target.path));
14866
+ if (!existsSync9(projectRoot) || !lstatSync16(projectRoot).isDirectory())
14731
14867
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
14732
14868
  assertSafePath(projectRoot);
14733
14869
  if (isAbsolute11(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep5}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
@@ -14736,8 +14872,8 @@ function selectNativeMigrationTargets(inventory, manifest) {
14736
14872
  if (identities.has(identity4))
14737
14873
  throw new Error(`Duplicate native migration target: ${target.path}`);
14738
14874
  identities.add(identity4);
14739
- const expected = canonicalSystemPath(resolve10(target.projectRoot, target.path));
14740
- const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve10(entry2.path) === expected);
14875
+ const expected = canonicalSystemPath(resolve11(target.projectRoot, target.path));
14876
+ const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve11(entry2.path) === expected);
14741
14877
  if (matches.length !== 1)
14742
14878
  throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
14743
14879
  const entry = matches[0];
@@ -14766,9 +14902,9 @@ function projectAncestorDirectories(projects) {
14766
14902
  }
14767
14903
  function inventoryNativeSkills(home = homedir2(), options = {}) {
14768
14904
  home = canonicalSystemPath(home);
14769
- if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute11(options.reviewedCacheAlias) || resolve10(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
14905
+ if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute11(options.reviewedCacheAlias) || resolve11(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
14770
14906
  throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
14771
- if (options.disabledVendorPaths?.some((path) => !isAbsolute11(path) || resolve10(path) !== path))
14907
+ if (options.disabledVendorPaths?.some((path) => !isAbsolute11(path) || resolve11(path) !== path))
14772
14908
  throw new Error("Disabled vendor paths must be exact absolute paths");
14773
14909
  const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
14774
14910
  const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
@@ -14776,14 +14912,18 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
14776
14912
  const selectedAgents = options.agents ? new Set(options.agents) : undefined;
14777
14913
  const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
14778
14914
  const rootDefinitions = selectedAgents ? ROOTS.filter(([agent, path]) => selectedAgents.has(agent) || selectedAgents.has("hermes") && agent === "codex" && path === ".agents/skills") : ROOTS;
14779
- const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join17(home, path), aliases)]);
14780
- const bridgePaths = Object.values(AGENT_ADAPTERS).map((adapter) => canonicalAgentPath(join17(home, adapter.root, CLI_BRIDGE_NAME), aliases));
14915
+ const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join18(home, path), aliases)]);
14916
+ const bridgePaths = Object.entries(AGENT_ADAPTERS).filter(([agent]) => agent !== "sumi" || includesAgent("sumi")).map(([agent, adapter]) => canonicalAgentPath(join18(agent === "sumi" ? sumiBridgeRoot(home) : join18(home, adapter.root), CLI_BRIDGE_NAME), aliases));
14781
14917
  for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
14782
14918
  for (const [agent, path] of rootDefinitions)
14783
- roots.push([agent, canonicalAgentPath(join17(project, path), aliases)]);
14919
+ roots.push([agent, canonicalAgentPath(join18(project, path), aliases)]);
14920
+ if (selectedAgents?.has("sumi"))
14921
+ for (const directory of [".claude", ".agents"])
14922
+ for (const name of ["skill", "skills"])
14923
+ roots.push(["sumi", canonicalAgentPath(join18(project, directory, name), aliases)]);
14784
14924
  }
14785
14925
  const installationInputs = options.codexInstallationInputRoots ?? [];
14786
- if (installationInputs.some((input) => resolve10(input) !== input || realpathSync6(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep5) || input.startsWith(path + sep5)))))
14926
+ if (installationInputs.some((input) => resolve11(input) !== input || realpathSync7(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep5) || input.startsWith(path + sep5)))))
14787
14927
  throw new Error("Native installation input overlaps an unconditional skill-loading root");
14788
14928
  const entries = [], seen = new Set;
14789
14929
  const cacheScans = new Map, maxAliasProofEntries = 1e4;
@@ -14797,13 +14937,13 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
14797
14937
  }
14798
14938
  let reviewedCacheAliasFound = false;
14799
14939
  function verifiedSiblingCacheAlias(agent, path, parent) {
14800
- const link = readlinkSync4(path), lexicalTarget = resolve10(parent, link);
14940
+ const link = readlinkSync4(path), lexicalTarget = resolve11(parent, link);
14801
14941
  if (isAbsolute11(link) ? link !== lexicalTarget : dirname11(link) !== ".")
14802
14942
  return false;
14803
14943
  const target = canonicalSystemPath(lexicalTarget);
14804
14944
  if (dirname11(target) !== parent)
14805
14945
  return false;
14806
- if (!lstatSync15(target, { throwIfNoEntry: false })?.isDirectory())
14946
+ if (!lstatSync16(target, { throwIfNoEntry: false })?.isDirectory())
14807
14947
  return false;
14808
14948
  const scan = cacheScans.get(target);
14809
14949
  if (!scan?.complete || scan.entries > maxAliasProofEntries)
@@ -14826,37 +14966,40 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
14826
14966
  assertSafePath(path);
14827
14967
  if (configuredRoot && agent === "codex" && installationInputs.some((root) => path === root || path.startsWith(`${root}${sep5}`)))
14828
14968
  return scan;
14829
- if (!existsSync8(path))
14969
+ if (!existsSync9(path))
14830
14970
  return scan;
14831
- const stat = lstatSync15(path);
14832
- if (stat.isFile())
14971
+ const stat = lstatSync16(path);
14972
+ if (stat.isFile()) {
14973
+ if (agent === "sumi" && depth === 1 && path.endsWith(".md"))
14974
+ throw new Error("NATIVE_SKILL_DRIFT: flat Sumi skill documents require a dedicated migration adapter");
14833
14975
  return scan;
14976
+ }
14834
14977
  if (!stat.isDirectory())
14835
14978
  throw new Error(`Unsupported native discovery entry: ${path}`);
14836
- if (existsSync8(join17(path, "SKILL.md"))) {
14979
+ if (existsSync9(join18(path, "SKILL.md"))) {
14837
14980
  scan.hasSkills = true;
14838
14981
  if (seen.has(path))
14839
14982
  return scan;
14840
14983
  seen.add(path);
14841
14984
  let managed = false;
14842
- const marker = join17(path, ".hasna-skills.json");
14843
- if (existsSync8(marker)) {
14985
+ const marker = join18(path, ".hasna-skills.json");
14986
+ if (existsSync9(marker)) {
14844
14987
  try {
14845
14988
  managed = JSON.parse(readFileSync12(marker, "utf8")).managedBy === "@hasna/skills";
14846
14989
  } catch {}
14847
14990
  }
14848
- const bridge = !vendor && isOwnedCliBridge(path, bridgePaths);
14991
+ const bridge = (!vendor || agent === "sumi") && isOwnedCliBridge(path, bridgePaths);
14849
14992
  const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep5));
14850
- entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join17(home, ".codex", "skills", ".system"), aliases) + sep5) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve10(home) } : {}, ...rootAlias ? { rootAlias } : {} });
14993
+ entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join18(home, ".codex", "skills", ".system"), aliases) + sep5) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve11(home) } : {}, ...rootAlias ? { rootAlias } : {} });
14851
14994
  return scan;
14852
14995
  }
14853
- if (depth > (vendor ? 32 : 3))
14996
+ if (depth > (agent === "sumi" ? 32 : vendor ? 32 : 3))
14854
14997
  return { ...scan, complete: false };
14855
14998
  const children = [], directory = opendirSync3(path);
14856
14999
  try {
14857
15000
  let child;
14858
15001
  while ((child = directory.readSync()) !== null) {
14859
- admit(join17(path, child.name));
15002
+ admit(join18(path, child.name));
14860
15003
  children.push(child);
14861
15004
  }
14862
15005
  } finally {
@@ -14868,13 +15011,13 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
14868
15011
  for (const { name } of children) {
14869
15012
  if (name === "node_modules")
14870
15013
  continue;
14871
- if (name.startsWith(".") && name !== ".system" && agent !== "hermes" && !(options.guardHermes && `${path}${sep5}`.includes(`${sep5}.agents${sep5}skills${sep5}`)))
15014
+ if (name.startsWith(".") && name !== ".system" && agent !== "hermes" && agent !== "sumi" && !(options.guardHermes && `${path}${sep5}`.includes(`${sep5}.agents${sep5}skills${sep5}`)))
14872
15015
  continue;
14873
15016
  const isVendor = vendor || name === ".system";
14874
15017
  if (isVendor && !options.includeVendor)
14875
15018
  continue;
14876
- const child = join17(path, name);
14877
- if (isVendor && lstatSync15(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
15019
+ const child = join18(path, name);
15020
+ if (isVendor && lstatSync16(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
14878
15021
  const target = statSync8(child, { throwIfNoEntry: false });
14879
15022
  if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent, child, path)) {
14880
15023
  scan.entries++;
@@ -14900,11 +15043,11 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
14900
15043
  scanRoot(agent, path);
14901
15044
  if (options.includeVendor) {
14902
15045
  for (const agent of ["codex", "claude"].filter(includesAgent))
14903
- scanRoot(agent, canonicalAgentPath(join17(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
15046
+ scanRoot(agent, canonicalAgentPath(join18(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
14904
15047
  if (includesAgent("claude"))
14905
- scanRoot("claude", canonicalAgentPath(join17(home, ".claude", "plugins", "synced"), aliases), true);
15048
+ scanRoot("claude", canonicalAgentPath(join18(home, ".claude", "plugins", "synced"), aliases), true);
14906
15049
  if (includesAgent("gemini"))
14907
- scanRoot("gemini", join17(home, ".gemini", "extensions"), true);
15050
+ scanRoot("gemini", join18(home, ".gemini", "extensions"), true);
14908
15051
  }
14909
15052
  const configured = options.configured ? INTEGRATION_AGENTS.filter(includesAgent).flatMap((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }).roots.map((path) => ({ agent, path }))) : [];
14910
15053
  for (const root of [...options.agentRoots ?? [], ...configured])
@@ -14917,7 +15060,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
14917
15060
  }
14918
15061
  function readOptional(path) {
14919
15062
  assertSafePath(path);
14920
- return existsSync8(path) ? readFileSync12(path, "utf8") : null;
15063
+ return existsSync9(path) ? readFileSync12(path, "utf8") : null;
14921
15064
  }
14922
15065
  function jsonObject(text2, path) {
14923
15066
  if (text2 === null)
@@ -15017,19 +15160,19 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
15017
15160
  function disableCodexSkills(text2, skills, aliases, bridgePath) {
15018
15161
  const bundled = disableCodexBundledSkills(text2);
15019
15162
  let result = normalizeCodexInlinePathConfig(bundled);
15020
- const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve10(bridgePath), resolve10(join17(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
15163
+ const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve11(bridgePath), resolve11(join18(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
15021
15164
  const previousConfig = Bun.TOML.parse(bundled).skills?.config;
15022
15165
  if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
15023
15166
  throw new Error("Codex skill controls require one path or name selector per [[skills.config]] entry; review ambiguous entries before running skills hook install");
15024
15167
  const bridgeNeedsRepair = previousConfig?.some((entry) => entry.enabled === false && bridgeSelector(entry));
15025
15168
  const selections = [...skills.filter((entry) => entry.agent === "codex" && !entry.bridge).map((skill) => ({ path: skill.path, enabled: false })), { path: bridgePath, enabled: true }];
15026
15169
  for (const skill of selections) {
15027
- const path = join17(skill.path, "SKILL.md");
15170
+ const path = join18(skill.path, "SKILL.md");
15028
15171
  let found = false;
15029
15172
  result = result.replace(CODEX_SKILL_CONFIG_SECTIONS, (section) => {
15030
15173
  const parsed = Bun.TOML.parse(section);
15031
15174
  const declared = parsed.skills?.config?.[0];
15032
- if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve10(path), resolve10(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
15175
+ if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve11(path), resolve11(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
15033
15176
  return section;
15034
15177
  found = true;
15035
15178
  return /^\s*enabled\s*=/m.test(section) ? section.replace(/^\s*enabled\s*=.*$/m, `enabled = ${skill.enabled}`) : `${section.trimEnd()}
@@ -15050,14 +15193,14 @@ enabled = false
15050
15193
  return result;
15051
15194
  }
15052
15195
  function assertCodexInstallationInputs(home, projectDirs, inputs) {
15053
- const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => resolve10(directory, path)));
15196
+ const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => resolve11(directory, path)));
15054
15197
  if (inputs.some((input) => nativeRoots.some((root) => root === input || root.startsWith(input + sep5) || input.startsWith(root + sep5))))
15055
15198
  throw new Error("Native installation input overlaps an unconditional skill-loading root");
15056
15199
  }
15057
15200
  function planAgentIntegration(options) {
15058
15201
  const home = options.home ?? homedir2(), dataDir2 = options.dataDir ?? getDataDirReadOnly();
15059
15202
  const aliases = rootAliases(home, options.allowRootAliases);
15060
- const policyPath = join17(dataDir2, "agent-policy.json");
15203
+ const policyPath = join18(dataDir2, "agent-policy.json");
15061
15204
  assertSafePath(policyPath);
15062
15205
  const priorSnapshot = readManagedSkillPolicySnapshot(dataDir2), previousPolicy = priorSnapshot?.text ?? null, policy = priorSnapshot?.value ?? {};
15063
15206
  if (policy.bridge !== undefined && (!policy.bridge || typeof policy.bridge !== "object" || Array.isArray(policy.bridge)))
@@ -15089,10 +15232,10 @@ function planAgentIntegration(options) {
15089
15232
  }
15090
15233
  return resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, retainedReview, canonical: (path) => canonicalAgentPath(path, aliases) });
15091
15234
  });
15092
- const codexConfig = options.agents.includes("codex") ? Bun.TOML.parse(readOptional(canonicalAgentPath(join17(home, ".codex", "config.toml"), aliases)) ?? "") : {};
15235
+ const codexConfig = options.agents.includes("codex") ? Bun.TOML.parse(readOptional(canonicalAgentPath(join18(home, ".codex", "config.toml"), aliases)) ?? "") : {};
15093
15236
  const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, disabledVendorPaths: disabledCodexSkillPaths(codexConfig, aliases) });
15094
15237
  const observedNativeSources = [];
15095
- const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join17(entry.path, "SKILL.md")), canonicalAgentPath(join17(home, ".codex/plugins/cache"), aliases), resolve10(options.projectDir ?? home), (path) => {
15238
+ const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join18(entry.path, "SKILL.md")), canonicalAgentPath(join18(home, ".codex/plugins/cache"), aliases), resolve11(options.projectDir ?? home), (path) => {
15096
15239
  const bytes = readNativeBytes(path, 1024 * 1024);
15097
15240
  observedNativeSources.push({ path, sha256: sha3(bytes) });
15098
15241
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
@@ -15100,7 +15243,7 @@ function planAgentIntegration(options) {
15100
15243
  const codexPluginSkills = codexPluginControls.skills;
15101
15244
  const codexInactivePlugins = codexPluginControls.inactivePlugins;
15102
15245
  const codexDiscovery = discoveries.find((binding) => binding.agent === "codex");
15103
- const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root) => root === input.sourceRoot || root.startsWith(input.sourceRoot + sep5) || input.sourceRoot.startsWith(root + sep5)) && codexDiscovery.sources.some((source) => source.path === join17(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
15246
+ const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root) => root === input.sourceRoot || root.startsWith(input.sourceRoot + sep5) || input.sourceRoot.startsWith(root + sep5)) && codexDiscovery.sources.some((source) => source.path === join18(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
15104
15247
  assertCodexInstallationInputs(home, [options.projectDir ?? home], codexPluginSourceInputs.map((input) => input.sourceRoot));
15105
15248
  const changes = [];
15106
15249
  for (const agent of [...new Set(options.agents)]) {
@@ -15108,19 +15251,19 @@ function planAgentIntegration(options) {
15108
15251
  throw new Error(`Unsupported agent: ${agent}`);
15109
15252
  const { command, profileId: profileId2 } = bindings.get(agent);
15110
15253
  const adapter = AGENT_ADAPTERS[agent];
15111
- const bridgePath = canonicalAgentPath(join17(home, adapter.root, CLI_BRIDGE_NAME), aliases);
15254
+ const bridgePath = canonicalAgentPath(join18(agent === "sumi" ? sumiBridgeRoot(home) : join18(home, adapter.root), CLI_BRIDGE_NAME), aliases);
15112
15255
  assertSafePath(bridgePath);
15113
- if (existsSync8(bridgePath) && !isOwnedCliBridge(bridgePath, [bridgePath]))
15256
+ if (existsSync9(bridgePath) && !isOwnedCliBridge(bridgePath, [bridgePath]))
15114
15257
  throw new Error(`Refusing to overwrite an unrecognized or modified Skills bridge: ${bridgePath}`);
15115
15258
  for (const [name, after2] of Object.entries(CLI_BRIDGE_FILES)) {
15116
- const path2 = join17(bridgePath, name), before2 = readOptional(path2);
15259
+ const path2 = join18(bridgePath, name), before2 = readOptional(path2);
15117
15260
  if (before2 !== after2)
15118
15261
  changes.push({ path: path2, before: before2, after: after2 });
15119
15262
  }
15120
- const path = canonicalAgentPath(join17(home, adapter.config), aliases);
15263
+ const path = canonicalAgentPath(agent === "sumi" ? sumiConfigPath(home) : join18(home, adapter.config), aliases);
15121
15264
  const before = readOptional(path);
15122
15265
  if (agent === "hermes") {
15123
- const supervisorPath = join17(dataDir2, "agent-hooks", "hermes.js"), supervisorBefore = readOptional(supervisorPath), supervisorAfter = renderHermesSupervisor(command, profileId2);
15266
+ const supervisorPath = join18(dataDir2, "agent-hooks", "hermes.js"), supervisorBefore = readOptional(supervisorPath), supervisorAfter = renderHermesSupervisor(command, profileId2);
15124
15267
  const priorCommand = policy.bridge?.commands?.hermes, priorProfile = policy.bridge?.profiles?.hermes ?? policy.profileId;
15125
15268
  const previous = policy.bridge?.supervisors?.hermes;
15126
15269
  if (supervisorBefore !== null && supervisorBefore !== supervisorAfter && !(previous?.path === supervisorPath && typeof priorCommand === "string" && typeof priorProfile === "string" && supervisorBefore === renderHermesSupervisor(priorCommand, priorProfile)))
@@ -15131,19 +15274,30 @@ function planAgentIntegration(options) {
15131
15274
  const after2 = configureHermesHooks(before, supervisor, previous);
15132
15275
  if (before !== after2)
15133
15276
  changes.push({ path, before, after: after2 });
15134
- const optOut = join17(home, ".hermes", HERMES_OPT_OUT), optOutBefore = readOptional(optOut);
15277
+ const optOut = join18(home, ".hermes", HERMES_OPT_OUT), optOutBefore = readOptional(optOut);
15135
15278
  if (optOutBefore === null)
15136
15279
  changes.push({ path: optOut, before: null, after: `Managed by @hasna/skills: bundled native skill reseeding is disabled.
15137
15280
  ` });
15138
15281
  continue;
15139
15282
  }
15140
15283
  const config = jsonObject(before, path);
15141
- if (agent === "opencode") {
15284
+ if (agent === "sumi") {
15285
+ if (config.permissions !== undefined && (!Array.isArray(config.permissions) || config.permissions.some((rule) => !rule || typeof rule.action !== "string" || typeof rule.resource !== "string" || !["allow", "deny", "ask"].includes(rule.effect))))
15286
+ throw new Error("Expected Sumi native permission rules");
15287
+ config.permissions = [...(config.permissions ?? []).filter((rule) => rule.action !== "skill"), ...SUMI_SKILL_PERMISSIONS];
15288
+ const pluginPath = join18(sumiConfigDirectory(home), "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
15289
+ const pluginAfter = renderSumiPlugin(command, profileId2);
15290
+ const priorCommand = policy.bridge?.commands?.sumi, priorProfile = policy.bridge?.profiles?.sumi ?? policy.profileId;
15291
+ if (pluginBefore !== null && pluginBefore !== pluginAfter && !(typeof priorCommand === "string" && typeof priorProfile === "string" && pluginBefore === renderSumiPlugin(priorCommand, priorProfile)))
15292
+ throw new Error("Refusing to overwrite a modified Sumi Skills plugin; preserve and review it first");
15293
+ if (pluginBefore !== pluginAfter)
15294
+ changes.push({ path: pluginPath, before: pluginBefore, after: pluginAfter });
15295
+ } else if (agent === "opencode") {
15142
15296
  const permission = config.permission ?? {};
15143
15297
  if (!permission || typeof permission !== "object" || Array.isArray(permission))
15144
15298
  throw new Error("Expected OpenCode permission object");
15145
15299
  config.permission = { ...permission, skill: { "*": "deny", [CLI_BRIDGE_NAME]: "allow" } };
15146
- const pluginPath = join17(home, ".config", "opencode", "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
15300
+ const pluginPath = join18(home, ".config", "opencode", "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
15147
15301
  const pluginAfter = renderOpenCodePlugin(command, profileId2);
15148
15302
  const priorCommand = policy.bridge?.commands?.opencode;
15149
15303
  const ownedPrevious = typeof priorCommand === "string" && typeof policy.profileId === "string" && pluginBefore === renderOpenCodePlugin(priorCommand, policy.bridge?.profiles?.opencode ?? policy.profileId);
@@ -15160,13 +15314,13 @@ function planAgentIntegration(options) {
15160
15314
  if (before !== after)
15161
15315
  changes.push({ path, before, after });
15162
15316
  if (agent === "codex") {
15163
- const configPath = canonicalAgentPath(join17(home, ".codex", "config.toml"), aliases), previous = readOptional(configPath);
15317
+ const configPath = canonicalAgentPath(join18(home, ".codex", "config.toml"), aliases), previous = readOptional(configPath);
15164
15318
  const next = disableReviewedCodexPluginNames(disableCodexSkills(previous ?? "", nativeSkills, aliases, bridgePath), codexPluginSkills);
15165
15319
  if (next !== (previous ?? ""))
15166
15320
  changes.push({ path: configPath, before: previous, after: next });
15167
15321
  }
15168
15322
  }
15169
- const codexPluginSkillReview = options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha3(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join17(home, ".codex/config.toml"), aliases))?.before === null ? null : sha3(readOptional(canonicalAgentPath(join17(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview;
15323
+ const codexPluginSkillReview = options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha3(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join18(home, ".codex/config.toml"), aliases))?.before === null ? null : sha3(readOptional(canonicalAgentPath(join18(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview;
15170
15324
  const discoveryAfter = discoveries.map((binding) => {
15171
15325
  const rebound = rebindAgentDiscovery(binding, new Map(changes.map((change) => [change.path, change.after])));
15172
15326
  if (binding.agent !== "codex")
@@ -15181,12 +15335,12 @@ function planAgentIntegration(options) {
15181
15335
  version: CLI_BRIDGE_VERSION,
15182
15336
  digest: CLI_BRIDGE_DIGEST,
15183
15337
  agents: [...new Set([...priorAgents, ...options.agents])].sort(),
15184
- home: resolve10(home),
15338
+ home: resolve11(home),
15185
15339
  includeVendor: true,
15186
- ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join17(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha3(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
15340
+ ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join18(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha3(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
15187
15341
  commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
15188
15342
  profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
15189
- disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join17(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
15343
+ disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join18(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
15190
15344
  rootAliases: aliases,
15191
15345
  ...options.codexNativeCatalog || codexPluginSkills.length || codexInactivePlugins.length || codexPluginSourceInputs.length ? { codexPluginSkills, codexInactivePlugins, codexPluginSkillReview } : {},
15192
15346
  discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
@@ -15209,7 +15363,7 @@ function claudeSettingsConsumers(home, path, discoveries, aliases) {
15209
15363
  const distance = relative5(canonical5(root), path);
15210
15364
  return distance === "" || distance !== ".." && !distance.startsWith(`..${sep5}`) && !isAbsolute11(distance);
15211
15365
  };
15212
- return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" || canonical5(join17(home, AGENT_ADAPTERS[binding.agent].config)) === path || binding.sources.some((source) => canonical5(source.path) === path) || binding.roots.some(containsSettings) || binding.directories?.some((directory) => containsSettings(directory.path))).map((binding) => binding.agent);
15366
+ return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" || canonical5(join18(home, AGENT_ADAPTERS[binding.agent].config)) === path || binding.sources.some((source) => canonical5(source.path) === path) || binding.roots.some(containsSettings) || binding.directories?.some((directory) => containsSettings(directory.path))).map((binding) => binding.agent);
15213
15367
  }
15214
15368
  function verifyCoordinatedDiscovery(binding, home, aliases) {
15215
15369
  try {
@@ -15226,8 +15380,8 @@ function verifyCoordinatedDiscovery(binding, home, aliases) {
15226
15380
  }
15227
15381
  }
15228
15382
  function planClaudeHookEventsUpdate(options) {
15229
- const home = resolve10(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
15230
- const policyPath = join17(dataDir2, "agent-policy.json");
15383
+ const home = resolve11(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
15384
+ const policyPath = join18(dataDir2, "agent-policy.json");
15231
15385
  assertSafePath(policyPath);
15232
15386
  const snapshot = readManagedSkillPolicySnapshot(dataDir2);
15233
15387
  if (!snapshot)
@@ -15238,9 +15392,9 @@ function planClaudeHookEventsUpdate(options) {
15238
15392
  }
15239
15393
  const aliases = bridge.rootAliases ?? [];
15240
15394
  recheckRootAliases(aliases);
15241
- const path = canonicalAgentPath(join17(home, ".claude", "settings.json"), aliases);
15395
+ const path = canonicalAgentPath(join18(home, ".claude", "settings.json"), aliases);
15242
15396
  assertSafePath(path);
15243
- const before = lstatSync15(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
15397
+ const before = lstatSync16(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
15244
15398
  if ((before === null ? "absent" : sha3(before)) !== options.expectedSettingsSha256)
15245
15399
  throw new Error("Claude settings preimage changed");
15246
15400
  assertClaudeHookEventsReplacement(before, options.replacement, options.events);
@@ -15300,14 +15454,14 @@ function atomicWrite2(path, content) {
15300
15454
  writeFileSync4(temporary, content, { mode: 384, flag: "wx" });
15301
15455
  renameSync2(temporary, path);
15302
15456
  } finally {
15303
- if (existsSync8(temporary))
15457
+ if (existsSync9(temporary))
15304
15458
  unlinkSync3(temporary);
15305
15459
  }
15306
15460
  }
15307
15461
  function planAgentSettingsWitnessUpgrade(options) {
15308
15462
  if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3].includes(options.targetCodexVersion)))
15309
15463
  throw new Error("Invalid Codex witness target version");
15310
- const home = resolve10(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
15464
+ const home = resolve11(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
15311
15465
  const snapshot = readManagedSkillPolicySnapshot(dataDir2);
15312
15466
  if (!snapshot || sha3(snapshot.text) !== options.expectedPolicySha256)
15313
15467
  throw new Error("Managed policy preimage changed");
@@ -15316,7 +15470,7 @@ function planAgentSettingsWitnessUpgrade(options) {
15316
15470
  const binding = policy.bridge?.discovery?.[options.agent];
15317
15471
  if (!binding || binding.agent !== options.agent || binding.method !== "reviewed")
15318
15472
  throw new Error("Settings witness upgrade requires an existing reviewed native binding");
15319
- const configPath = canonicalAgentPath(join17(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
15473
+ const configPath = canonicalAgentPath(join18(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
15320
15474
  const settings = readOptional(configPath);
15321
15475
  if (settings === null || sha3(settings) !== options.expectedSettingsSha256)
15322
15476
  throw new Error("Native settings preimage changed");
@@ -15355,7 +15509,7 @@ function planAgentSettingsWitnessUpgrade(options) {
15355
15509
  const replacement = { ...binding, sources: rebound };
15356
15510
  verifyAgentDiscovery(replacement);
15357
15511
  const after = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
15358
- return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join17(dataDir2, "agent-policy.json"), before: snapshot.text, after }], nativeSkills: [], observedPolicy: { path: join17(dataDir2, "agent-policy.json"), before: snapshot.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
15512
+ return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join18(dataDir2, "agent-policy.json"), before: snapshot.text, after }], nativeSkills: [], observedPolicy: { path: join18(dataDir2, "agent-policy.json"), before: snapshot.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
15359
15513
  }
15360
15514
  function applyAgentIntegration(plan) {
15361
15515
  for (const source of plan.observedNativeSources ?? [])
@@ -15363,12 +15517,12 @@ function applyAgentIntegration(plan) {
15363
15517
  throw new Error("Native identity source changed after planning");
15364
15518
  if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
15365
15519
  throw new Error("Native settings changed after witness planning");
15366
- const policyPath = join17(plan.dataDir, "agent-policy.json");
15520
+ const policyPath = join18(plan.dataDir, "agent-policy.json");
15367
15521
  assertSafePath(policyPath);
15368
- const currentText = (path) => resolve10(path) === resolve10(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
15522
+ const currentText = (path) => resolve11(path) === resolve11(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
15369
15523
  readManagedSkillPolicySnapshot(plan.dataDir);
15370
15524
  for (const change of plan.changes)
15371
- if (resolve10(change.path) === resolve10(policyPath))
15525
+ if (resolve11(change.path) === resolve11(policyPath))
15372
15526
  parseManagedSkillPolicy(change.after);
15373
15527
  const aliases = plan.rootAliases ?? [];
15374
15528
  recheckRootAliases(aliases);
@@ -15397,7 +15551,7 @@ function applyAgentIntegration(plan) {
15397
15551
  for (const change of plan.changes)
15398
15552
  if (currentText(change.path) !== change.before)
15399
15553
  throw new Error(`Configuration changed after planning: ${change.path}`);
15400
- const backupRoot = join17(plan.dataDir, "migration", randomUUID2()), backups = [], written = [], createdDirectories = new Set;
15554
+ const backupRoot = join18(plan.dataDir, "migration", randomUUID2()), backups = [], written = [], createdDirectories = new Set;
15401
15555
  if (!plan.changes.length) {
15402
15556
  recheckRootAliases(aliases);
15403
15557
  return { changed: [], backups, ...aliases.length ? { rootAliases: aliases } : {} };
@@ -15407,7 +15561,7 @@ function applyAgentIntegration(plan) {
15407
15561
  chmodSync(backupRoot, 448);
15408
15562
  for (const [index, change] of plan.changes.entries())
15409
15563
  if (change.before !== null) {
15410
- const backup = join17(backupRoot, `${index}-${sha3(change.path).slice(0, 12)}.backup`);
15564
+ const backup = join18(backupRoot, `${index}-${sha3(change.path).slice(0, 12)}.backup`);
15411
15565
  writeFileSync4(backup, change.before, { mode: 384, flag: "wx" });
15412
15566
  if (readFileSync12(backup, "utf8") !== change.before)
15413
15567
  throw new Error("Native configuration preservation readback failed");
@@ -15418,7 +15572,7 @@ function applyAgentIntegration(plan) {
15418
15572
  recheckRootAliases(aliases);
15419
15573
  if (currentText(change.path) !== change.before)
15420
15574
  throw new Error(`Configuration changed after planning: ${change.path}`);
15421
- for (let directory = dirname11(change.path);!existsSync8(directory); directory = dirname11(directory))
15575
+ for (let directory = dirname11(change.path);!existsSync9(directory); directory = dirname11(directory))
15422
15576
  createdDirectories.add(directory);
15423
15577
  const after = change.after;
15424
15578
  atomicWrite2(change.path, after);
@@ -15438,7 +15592,7 @@ function applyAgentIntegration(plan) {
15438
15592
  }
15439
15593
  for (const agent of plan.managedAgentChecks?.agents ?? [])
15440
15594
  assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
15441
- atomicWrite2(join17(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha3(change.before), afterHash: sha3(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
15595
+ atomicWrite2(join18(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha3(change.before), afterHash: sha3(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
15442
15596
  `);
15443
15597
  } catch (error) {
15444
15598
  for (const change of written.reverse()) {
@@ -15492,7 +15646,7 @@ function writeArchiveJournal(path, value) {
15492
15646
  } finally {
15493
15647
  if (descriptor !== undefined)
15494
15648
  closeSync8(descriptor);
15495
- if (lstatSync15(temporary, { throwIfNoEntry: false }))
15649
+ if (lstatSync16(temporary, { throwIfNoEntry: false }))
15496
15650
  unlinkSync3(temporary);
15497
15651
  }
15498
15652
  }
@@ -15503,7 +15657,7 @@ function archiveNativeSkills(inventory, options) {
15503
15657
  recheckRootAliases(aliases);
15504
15658
  for (const entry of inventory.filter((entry2) => entry2.bridge)) {
15505
15659
  const adapter = AGENT_ADAPTERS[entry.agent];
15506
- const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join17(entry.bridgeHome, adapter.root, CLI_BRIDGE_NAME), aliases) : undefined;
15660
+ const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join18(entry.agent === "sumi" ? sumiBridgeRoot(entry.bridgeHome) : join18(entry.bridgeHome, adapter.root), CLI_BRIDGE_NAME), aliases) : undefined;
15507
15661
  if (!expected || treeHash(entry.path) !== entry.hash || !isOwnedCliBridge(entry.path, [expected]))
15508
15662
  throw new Error(`Skills bridge changed after planning: ${entry.path}`);
15509
15663
  }
@@ -15514,11 +15668,11 @@ function archiveNativeSkills(inventory, options) {
15514
15668
  const targetManifest = options.targetManifest ? { schema: options.targetManifest.schema, digest: options.targetManifest.digest, targetCount: options.targetManifest.targets.length } : undefined;
15515
15669
  if (!selected.length)
15516
15670
  return { entries: [], ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
15517
- const operationId = randomUUID2(), archiveRoot = join17(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join17(archiveRoot, "receipt.json");
15671
+ const operationId = randomUUID2(), archiveRoot = join18(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join18(archiveRoot, "receipt.json");
15518
15672
  const entries = selected.map((entry, index) => ({
15519
- source: entry.vendor ? join17(entry.path, "SKILL.md") : entry.path,
15520
- archive: join17(archiveRoot, `${index}-${sha3(entry.path).slice(0, 12)}`),
15521
- hash: entry.vendor ? sha3(readNativeBytes(join17(entry.path, "SKILL.md"))) : entry.hash,
15673
+ source: entry.vendor ? join18(entry.path, "SKILL.md") : entry.path,
15674
+ archive: join18(archiveRoot, `${index}-${sha3(entry.path).slice(0, 12)}`),
15675
+ hash: entry.vendor ? sha3(readNativeBytes(join18(entry.path, "SKILL.md"))) : entry.hash,
15522
15676
  ...entry.vendor ? { discoveryOnly: true } : {},
15523
15677
  status: "planned"
15524
15678
  }));
@@ -15526,7 +15680,7 @@ function archiveNativeSkills(inventory, options) {
15526
15680
  const moved = [];
15527
15681
  const verifyArchive = (entry) => {
15528
15682
  assertSafePath(entry.archive);
15529
- const stat = lstatSync15(entry.archive);
15683
+ const stat = lstatSync16(entry.archive);
15530
15684
  if (entry.discoveryOnly ? !stat.isFile() : !stat.isDirectory())
15531
15685
  throw new Error("Archive type changed");
15532
15686
  if ((entry.discoveryOnly ? sha3(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
@@ -15534,7 +15688,7 @@ function archiveNativeSkills(inventory, options) {
15534
15688
  };
15535
15689
  assertSafePath(archiveRoot);
15536
15690
  const created = [];
15537
- for (let path = archiveRoot;!existsSync8(path); path = dirname11(path))
15691
+ for (let path = archiveRoot;!existsSync9(path); path = dirname11(path))
15538
15692
  created.push(path);
15539
15693
  mkdirSync5(archiveRoot, { recursive: true, mode: 448 });
15540
15694
  try {
@@ -15574,7 +15728,7 @@ function archiveNativeSkills(inventory, options) {
15574
15728
  recheckRootAliases(aliases);
15575
15729
  assertSafePath(entry.source);
15576
15730
  assertSafePath(entry.archive);
15577
- if (lstatSync15(entry.source, { throwIfNoEntry: false })) {
15731
+ if (lstatSync16(entry.source, { throwIfNoEntry: false })) {
15578
15732
  entry.status = "recovery-required";
15579
15733
  entry.conflict = "source-occupied";
15580
15734
  continue;
@@ -15591,7 +15745,7 @@ function archiveNativeSkills(inventory, options) {
15591
15745
  syncArchiveDirectory(dirname11(entry.source));
15592
15746
  unlinkSync3(entry.archive);
15593
15747
  } else {
15594
- if (lstatSync15(entry.source, { throwIfNoEntry: false })) {
15748
+ if (lstatSync16(entry.source, { throwIfNoEntry: false })) {
15595
15749
  entry.status = "recovery-required";
15596
15750
  entry.conflict = "source-occupied";
15597
15751
  continue;
@@ -15622,8 +15776,8 @@ function assertManagedAgentBridge(agent, options = {}) {
15622
15776
  assertManagedAgentBridgeWithDiscovery(agent, options);
15623
15777
  }
15624
15778
  function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscovery) {
15625
- const home = resolve10(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
15626
- assertSafePath(join17(dataDir2, "agent-policy.json"));
15779
+ const home = resolve11(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
15780
+ assertSafePath(join18(dataDir2, "agent-policy.json"));
15627
15781
  const snapshot = readManagedSkillPolicySnapshot(dataDir2);
15628
15782
  if (!snapshot)
15629
15783
  throw new Error("NATIVE_SKILL_DRIFT: install the Skills bridge with skills hook install");
@@ -15634,14 +15788,14 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
15634
15788
  if (!Array.isArray(aliases))
15635
15789
  throw new Error("NATIVE_SKILL_DRIFT: invalid root alias binding");
15636
15790
  recheckRootAliases(aliases);
15637
- const expected = canonicalAgentPath(join17(home, AGENT_ADAPTERS[agent].root, CLI_BRIDGE_NAME), aliases);
15791
+ const expected = canonicalAgentPath(join18(agent === "sumi" ? sumiBridgeRoot(home) : join18(home, AGENT_ADAPTERS[agent].root), CLI_BRIDGE_NAME), aliases);
15638
15792
  if (!isOwnedCliBridge(expected, [expected]))
15639
15793
  throw new Error("NATIVE_SKILL_DRIFT: the native Skills bridge is missing or modified; repair it before continuing");
15640
15794
  const roots = projectAncestorDirectories([options.projectDir ?? process.cwd(), ...options.projectDirs ?? [], ...agent === "hermes" && process.env.TERMINAL_CWD ? [process.cwd()] : []]);
15641
- const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes"].includes(agent) && entry.path.includes(`${sep5}.agents${sep5}skills${sep5}`) || agent === "opencode" && entry.agent === "claude";
15795
+ const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes", "sumi"].includes(agent) && entry.path.includes(`${sep5}.agents${sep5}skills${sep5}`) || ["opencode", "sumi"].includes(agent) && entry.agent === "claude";
15642
15796
  const discovery = provenDiscovery ?? binding.discovery?.[agent];
15643
15797
  assertProjectDiscovery(agent, [...roots], home, (path) => canonicalAgentPath(path, aliases), discovery);
15644
- const configPath = canonicalAgentPath(join17(home, AGENT_ADAPTERS[agent].config), aliases), config = agent === "hermes" ? parseHermesConfig(readOptional(configPath)) : jsonObject(readOptional(configPath), configPath);
15798
+ const configPath = canonicalAgentPath(agent === "sumi" ? sumiConfigPath(home) : join18(home, AGENT_ADAPTERS[agent].config), aliases), config = agent === "hermes" ? parseHermesConfig(readOptional(configPath)) : jsonObject(readOptional(configPath), configPath);
15645
15799
  const command = binding.commands?.[agent], profile = binding.profiles?.[agent];
15646
15800
  if (typeof command !== "string" || typeof profile !== "string")
15647
15801
  throw new Error("NATIVE_SKILL_DRIFT: the native hook command/profile binding is missing");
@@ -15649,11 +15803,14 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
15649
15803
  throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
15650
15804
  if (agent === "hermes") {
15651
15805
  const supervisor = binding.supervisors?.hermes;
15652
- if (supervisor?.path !== join17(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha3(renderHermesSupervisor(command, profile)))
15806
+ if (supervisor?.path !== join18(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha3(renderHermesSupervisor(command, profile)))
15653
15807
  throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
15654
15808
  assertHermesProtection(home, config, command, profile, supervisor);
15809
+ } else if (agent === "sumi") {
15810
+ if (JSON.stringify(config.permissions?.filter((rule) => rule.action === "skill")) !== JSON.stringify(SUMI_SKILL_PERMISSIONS) || readOptional(join18(sumiConfigDirectory(home), "plugins", "skills-cli.js")) !== renderSumiPlugin(command, profile))
15811
+ throw new Error("NATIVE_SKILL_DRIFT: Sumi bridge protection changed; run skills hook install");
15655
15812
  } else if (agent === "opencode") {
15656
- if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(join17(home, ".config", "opencode", "plugins", "skills-cli.js")) !== renderOpenCodePlugin(command, profile))
15813
+ if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(join18(home, ".config", "opencode", "plugins", "skills-cli.js")) !== renderOpenCodePlugin(command, profile))
15657
15814
  throw new Error("NATIVE_SKILL_DRIFT: OpenCode bridge protection changed; run skills hook install");
15658
15815
  } else {
15659
15816
  const required = {};
@@ -15670,21 +15827,21 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
15670
15827
  if (agent === "gemini" && (config.hooksConfig?.enabled === false || config.skills?.enabled !== true || !["antigravity-support", "skill-creator"].every((name) => config.skills?.disabled?.includes(name)) || config.skills?.disabled?.includes(CLI_BRIDGE_NAME)))
15671
15828
  throw new Error("NATIVE_SKILL_DRIFT: Gemini bridge or bundled-skill protection changed; run skills hook install");
15672
15829
  }
15673
- const codexPath = canonicalAgentPath(join17(home, ".codex", "config.toml"), aliases);
15830
+ const codexPath = canonicalAgentPath(join18(home, ".codex", "config.toml"), aliases);
15674
15831
  if (options.codexDiscoveryRecovery && (agent !== "codex" || options.codexDiscoveryRecovery.configPath !== codexPath))
15675
15832
  throw new Error("NATIVE_SKILL_DRIFT: Codex trust recovery names a different configuration root");
15676
15833
  const codexConfig = agent === "codex" ? Bun.TOML.parse(readOptional(codexPath) ?? "") : {};
15677
15834
  if (agent === "codex" && codexConfig.skills?.bundled?.enabled !== false)
15678
15835
  throw new Error("NATIVE_SKILL_DRIFT: Codex bundled skill reseeding is not disabled (skills.bundled.enabled); run skills hook install");
15679
- const setting = (path) => (codexConfig.skills?.config ?? []).filter((entry) => typeof entry.path === "string" && [path, join17(path, "SKILL.md")].includes(canonicalAgentPath(entry.path, aliases)));
15836
+ const setting = (path) => (codexConfig.skills?.config ?? []).filter((entry) => typeof entry.path === "string" && [path, join18(path, "SKILL.md")].includes(canonicalAgentPath(entry.path, aliases)));
15680
15837
  if (agent === "codex" && [...setting(expected), ...(codexConfig.skills?.config ?? []).filter((entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME)].some((entry) => entry.enabled === false))
15681
15838
  throw new Error("NATIVE_SKILL_DRIFT: the Codex CLI bridge is disabled; run skills hook install");
15682
- if (agent === "codex" && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join17(home, ".codex/plugins/cache"), aliases), binding.codexPluginSkills ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024))))
15839
+ if (agent === "codex" && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join18(home, ".codex/plugins/cache"), aliases), binding.codexPluginSkills ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024))))
15683
15840
  throw new Error("NATIVE_SKILL_DRIFT: reviewed native plugin capability controls changed; run skills hook install with a fresh discovery review");
15684
15841
  const disabledPlugin = (entry) => {
15685
15842
  if (agent !== "codex" || !entry.vendor)
15686
15843
  return false;
15687
- const document2 = join17(entry.path, "SKILL.md"), cache = canonicalAgentPath(join17(home, ".codex/plugins/cache"), aliases), read2 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024));
15844
+ const document2 = join18(entry.path, "SKILL.md"), cache = canonicalAgentPath(join18(home, ".codex/plugins/cache"), aliases), read2 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024));
15688
15845
  return isReviewedCodexPluginInactive(document2, cache, binding.codexInactivePlugins ?? [], codexConfig.plugins, codexConfig.skills?.config ?? [], read2) || isReviewedCodexPluginSkillDisabled(document2, cache, binding.codexPluginSkills ?? [], codexConfig.skills?.config, read2);
15689
15846
  };
15690
15847
  const disabledPaths = new Set(disabledCodexSkillPaths(codexConfig, aliases));
@@ -15697,15 +15854,15 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
15697
15854
  return true;
15698
15855
  if (!disabledPaths.has(entry.path))
15699
15856
  return false;
15700
- if (entry.path.startsWith(canonicalAgentPath(join17(home, ".codex", "plugins", "cache"), aliases) + sep5))
15857
+ if (entry.path.startsWith(canonicalAgentPath(join18(home, ".codex", "plugins", "cache"), aliases) + sep5))
15701
15858
  return true;
15702
- const runtimeCache = canonicalAgentPath(join17(home, ".cache", "codex-runtimes"), aliases);
15859
+ const runtimeCache = canonicalAgentPath(join18(home, ".cache", "codex-runtimes"), aliases);
15703
15860
  if (entry.path.startsWith(runtimeCache + sep5) && discovery?.method === "automatic" && discovery.roots.some((root) => entry.path.startsWith(root + sep5)))
15704
15861
  return true;
15705
- const bundledMarketplaces = canonicalAgentPath(join17(home, ".codex", ".tmp", "bundled-marketplaces"), aliases);
15862
+ const bundledMarketplaces = canonicalAgentPath(join18(home, ".codex", ".tmp", "bundled-marketplaces"), aliases);
15706
15863
  if (entry.path.startsWith(bundledMarketplaces + sep5) && discovery?.method === "automatic" && discovery.roots.some((root) => entry.path.startsWith(root + sep5)))
15707
15864
  return true;
15708
- if (!entry.path.startsWith(canonicalAgentPath(join17(home, ".codex", "skills", ".system"), aliases) + sep5))
15865
+ if (!entry.path.startsWith(canonicalAgentPath(join18(home, ".codex", "skills", ".system"), aliases) + sep5))
15709
15866
  return false;
15710
15867
  return Array.isArray(binding.disabledBuiltins) && binding.disabledBuiltins.some((item) => item.path === entry.path && item.hash === entry.hash);
15711
15868
  };
@@ -15715,6 +15872,8 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
15715
15872
  throw new Error("NATIVE_SKILL_DRIFT: an installed Gemini builtin is not disabled");
15716
15873
  try {
15717
15874
  verifyAgentDiscovery(discovery, options.codexDiscoveryRecovery);
15875
+ if (agent === "sumi" && discovery.method === "reviewed")
15876
+ resolveAgentDiscovery({ home, agent, retainedReview: discovery, canonical: (path) => canonicalAgentPath(path, aliases) });
15718
15877
  if (discovery.method === "automatic") {
15719
15878
  const current = resolveAgentDiscovery({ home, agent, canonical: (path) => canonicalAgentPath(path, aliases) });
15720
15879
  if (JSON.stringify(current) !== JSON.stringify(discovery))
@@ -15726,7 +15885,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
15726
15885
  let installationInputRoots = [];
15727
15886
  if (agent === "codex") {
15728
15887
  try {
15729
- installationInputRoots = reviewedCodexPluginSourceRoots(canonicalAgentPath(join17(home, ".codex/plugins/cache"), aliases), discovery.codexInstallationInputs?.plugins ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
15888
+ installationInputRoots = reviewedCodexPluginSourceRoots(canonicalAgentPath(join18(home, ".codex/plugins/cache"), aliases), discovery.codexInstallationInputs?.plugins ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
15730
15889
  } catch {
15731
15890
  throw new Error("NATIVE_SKILL_DRIFT: native installation input identity changed; review discovery and catalog");
15732
15891
  }
@@ -15761,9 +15920,9 @@ function isSkillsOwnershipMarker(marker) {
15761
15920
  return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
15762
15921
  }
15763
15922
  function hasSkillsOwnershipMarker(dir) {
15764
- const path = join18(dir, SYNC_MARKER_FILE);
15923
+ const path = join19(dir, SYNC_MARKER_FILE);
15765
15924
  try {
15766
- if (!lstatSync16(path).isFile())
15925
+ if (!lstatSync17(path).isFile())
15767
15926
  return false;
15768
15927
  const marker = JSON.parse(readFileSync13(path, "utf8"));
15769
15928
  return isSkillsOwnershipMarker(marker);
@@ -15785,9 +15944,9 @@ function resolveSyncAgents(arg) {
15785
15944
  function agentGlobalSkillsDir(agent, homeDir2 = homedir3()) {
15786
15945
  switch (agent) {
15787
15946
  case "opencode":
15788
- return join18(homeDir2, ".config", "opencode", "skills");
15947
+ return join19(homeDir2, ".config", "opencode", "skills");
15789
15948
  default:
15790
- return join18(homeDir2, `.${agent}`, "skills");
15949
+ return join19(homeDir2, `.${agent}`, "skills");
15791
15950
  }
15792
15951
  }
15793
15952
  function adaptSkillMdForAgent(skillMd, agent) {
@@ -15846,8 +16005,8 @@ function resolveSyncCorpus(options = {}) {
15846
16005
  function packageSourceRoots(source) {
15847
16006
  const roots = [];
15848
16007
  for (const sub of ["skills"]) {
15849
- const candidate = join18(source, sub);
15850
- if (existsSync9(candidate) && isDirectory(candidate))
16008
+ const candidate = join19(source, sub);
16009
+ if (existsSync10(candidate) && isDirectory(candidate))
15851
16010
  roots.push(candidate);
15852
16011
  }
15853
16012
  if (roots.length > 0)
@@ -15862,10 +16021,10 @@ function containsSkillDirectories(path) {
15862
16021
  return false;
15863
16022
  }
15864
16023
  return entries.some((entry) => {
15865
- const candidate = join18(path, entry);
16024
+ const candidate = join19(path, entry);
15866
16025
  if (!isDirectory(candidate))
15867
16026
  return false;
15868
- return existsSync9(join18(candidate, "SKILL.md")) || existsSync9(join18(candidate, "skill.json")) || existsSync9(join18(candidate, "package.json"));
16027
+ return existsSync10(join19(candidate, "SKILL.md")) || existsSync10(join19(candidate, "skill.json")) || existsSync10(join19(candidate, "package.json"));
15869
16028
  });
15870
16029
  }
15871
16030
  function isDirectory(path) {
@@ -15905,7 +16064,7 @@ function syncSkillsToAgents(options = {}) {
15905
16064
  actions.push({
15906
16065
  skill: name,
15907
16066
  agent,
15908
- path: join18(agentGlobalSkillsDir(agent, homeDir2), name, "SKILL.md"),
16067
+ path: join19(agentGlobalSkillsDir(agent, homeDir2), name, "SKILL.md"),
15909
16068
  action: "skip",
15910
16069
  reason: "not found in this machine's corpus"
15911
16070
  });
@@ -15935,7 +16094,7 @@ function syncSkillsToAgents(options = {}) {
15935
16094
  }
15936
16095
  function writeManagedAgentSkill(params) {
15937
16096
  const homeDir2 = params.homeDir ?? homedir3();
15938
- const dir = join18(agentGlobalSkillsDir(params.agent, homeDir2), params.skill);
16097
+ const dir = join19(agentGlobalSkillsDir(params.agent, homeDir2), params.skill);
15939
16098
  const result = writeManagedSkillDir(dir, params.skillMd, {
15940
16099
  skill: params.skill,
15941
16100
  source: params.source,
@@ -15952,11 +16111,11 @@ function writeManagedAgentSkill(params) {
15952
16111
  };
15953
16112
  }
15954
16113
  function writeManagedSkillDir(dir, skillMd, options) {
15955
- const skillMdPath = join18(dir, "SKILL.md");
15956
- const markerPath = join18(dir, SYNC_MARKER_FILE);
15957
- const dirExists = existsSync9(dir);
16114
+ const skillMdPath = join19(dir, "SKILL.md");
16115
+ const markerPath = join19(dir, SYNC_MARKER_FILE);
16116
+ const dirExists = existsSync10(dir);
15958
16117
  const managed = hasSkillsOwnershipMarker(dir);
15959
- const hasSkillMd = existsSync9(skillMdPath);
16118
+ const hasSkillMd = existsSync10(skillMdPath);
15960
16119
  if (dirExists && !managed && !hasSkillMd) {
15961
16120
  return {
15962
16121
  action: "skip",
@@ -15968,7 +16127,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
15968
16127
  return {
15969
16128
  action: "skip",
15970
16129
  path: skillMdPath,
15971
- reason: existsSync9(markerPath) ? "an unmanaged SKILL.md already exists here (invalid or foreign ownership marker); pass --force to overwrite" : "an unmanaged SKILL.md already exists here (hand-authored); pass --force to overwrite"
16130
+ reason: existsSync10(markerPath) ? "an unmanaged SKILL.md already exists here (invalid or foreign ownership marker); pass --force to overwrite" : "an unmanaged SKILL.md already exists here (hand-authored); pass --force to overwrite"
15972
16131
  };
15973
16132
  }
15974
16133
  if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
@@ -15991,11 +16150,11 @@ function writeManagedSkillDir(dir, skillMd, options) {
15991
16150
  return { action, path: skillMdPath };
15992
16151
  const parentDir = dirname12(dir);
15993
16152
  mkdirSync6(parentDir, { recursive: true });
15994
- const transactionDir = mkdtempSync(join18(parentDir, `.hasna-skills-write-${basename6(dir)}-`));
15995
- const candidateDir = join18(transactionDir, "candidate");
15996
- const backupDir = join18(transactionDir, "backup");
15997
- const candidateSkillMdPath = join18(candidateDir, "SKILL.md");
15998
- const candidateMarkerPath = join18(candidateDir, SYNC_MARKER_FILE);
16153
+ const transactionDir = mkdtempSync(join19(parentDir, `.hasna-skills-write-${basename6(dir)}-`));
16154
+ const candidateDir = join19(transactionDir, "candidate");
16155
+ const backupDir = join19(transactionDir, "backup");
16156
+ const candidateSkillMdPath = join19(candidateDir, "SKILL.md");
16157
+ const candidateMarkerPath = join19(candidateDir, SYNC_MARKER_FILE);
15999
16158
  const marker = {
16000
16159
  managedBy: SYNC_MARKER_MANAGED_BY,
16001
16160
  skill: options.skill,
@@ -16022,9 +16181,9 @@ function writeManagedSkillDir(dir, skillMd, options) {
16022
16181
  }
16023
16182
  renameDirectory(candidateDir, dir);
16024
16183
  } catch (error) {
16025
- if (originalMoved && existsSync9(backupDir)) {
16184
+ if (originalMoved && existsSync10(backupDir)) {
16026
16185
  try {
16027
- if (existsSync9(dir))
16186
+ if (existsSync10(dir))
16028
16187
  rmSync(dir, { recursive: true, force: true });
16029
16188
  renameDirectory(backupDir, dir);
16030
16189
  originalMoved = false;
@@ -16044,7 +16203,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
16044
16203
  return { action, path: skillMdPath };
16045
16204
  }
16046
16205
  function removeManagedAgentSkill(skill, agent, homeDir2 = homedir3()) {
16047
- const dir = join18(agentGlobalSkillsDir(agent, homeDir2), skill);
16206
+ const dir = join19(agentGlobalSkillsDir(agent, homeDir2), skill);
16048
16207
  if (!hasSkillsOwnershipMarker(dir))
16049
16208
  return false;
16050
16209
  rmSync(dir, { recursive: true, force: true });
@@ -16052,8 +16211,8 @@ function removeManagedAgentSkill(skill, agent, homeDir2 = homedir3()) {
16052
16211
  }
16053
16212
  function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = false) {
16054
16213
  if (kind === undefined || kind === "instruction" || preferBundledDocs) {
16055
- const skillMdPath = join18(skillPath, "SKILL.md");
16056
- if (existsSync9(skillMdPath))
16214
+ const skillMdPath = join19(skillPath, "SKILL.md");
16215
+ if (existsSync10(skillMdPath))
16057
16216
  return readFileSync13(skillMdPath, "utf-8");
16058
16217
  }
16059
16218
  return pointerSkillMd(name, description);
@@ -16094,8 +16253,8 @@ function resolveSkillAlias(name) {
16094
16253
  }
16095
16254
 
16096
16255
  // src/lib/project-state.ts
16097
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync14, writeFileSync as writeFileSync6 } from "fs";
16098
- import { join as join19 } from "path";
16256
+ import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync14, writeFileSync as writeFileSync6 } from "fs";
16257
+ import { join as join20 } from "path";
16099
16258
  var VALID_PIN_SOURCES = [
16100
16259
  "official",
16101
16260
  "custom",
@@ -16110,14 +16269,14 @@ var SKILLS_PROJECT_DIR = ".skills";
16110
16269
  var PROJECT_CONFIG_FILE = "project.json";
16111
16270
  var DEFAULT_EXPORT_DIR = ".skills/exports";
16112
16271
  function getProjectStateDir(targetDir = process.cwd()) {
16113
- return join19(targetDir, SKILLS_PROJECT_DIR);
16272
+ return join20(targetDir, SKILLS_PROJECT_DIR);
16114
16273
  }
16115
16274
  function getProjectConfigPath(targetDir = process.cwd()) {
16116
- return join19(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
16275
+ return join20(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
16117
16276
  }
16118
16277
  function loadProjectConfig(targetDir = process.cwd()) {
16119
16278
  const path = getProjectConfigPath(targetDir);
16120
- if (!existsSync10(path))
16279
+ if (!existsSync11(path))
16121
16280
  return null;
16122
16281
  try {
16123
16282
  return normalizeProjectConfig(JSON.parse(readFileSync14(path, "utf-8")));
@@ -16242,19 +16401,19 @@ function getSkillPath(name) {
16242
16401
  const extensionPath = findExtensionSkillPath(skillName);
16243
16402
  if (extensionPath)
16244
16403
  return extensionPath;
16245
- return join20(getPortableSkillsRoot(), skillName);
16404
+ return join21(getPortableSkillsRoot(), skillName);
16246
16405
  }
16247
16406
  function getCanonicalSkillName(name) {
16248
16407
  return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
16249
16408
  }
16250
16409
  function skillExists(name) {
16251
- return existsSync11(getSkillPath(name));
16410
+ return existsSync12(getSkillPath(name));
16252
16411
  }
16253
16412
  function installSkill(name, options = {}) {
16254
16413
  const { targetDir = process.cwd(), overwrite = false } = options;
16255
16414
  const canonicalName = getCanonicalSkillName(name);
16256
16415
  const skillName = normalizeSkillName(canonicalName);
16257
- if (!existsSync11(getSkillPath(name))) {
16416
+ if (!existsSync12(getSkillPath(name))) {
16258
16417
  const knownOfficial = Boolean(getSkill(name));
16259
16418
  return {
16260
16419
  skill: canonicalName,
@@ -16281,7 +16440,7 @@ function installSkill(name, options = {}) {
16281
16440
  }
16282
16441
  function installSkillSource(name, _options = {}) {
16283
16442
  const canonicalName = getCanonicalSkillName(name);
16284
- if (!existsSync11(getSkillPath(name))) {
16443
+ if (!existsSync12(getSkillPath(name))) {
16285
16444
  return { skill: canonicalName, success: false, error: `Skill '${name}' not found`, mode: "source" };
16286
16445
  }
16287
16446
  return {
@@ -16302,11 +16461,11 @@ function installSkillManifest(manifest, _options = {}) {
16302
16461
  }
16303
16462
  function createLocalSkillManifest(name, generateSkillMd) {
16304
16463
  const sourcePath = getSkillPath(name);
16305
- if (!existsSync11(sourcePath))
16464
+ if (!existsSync12(sourcePath))
16306
16465
  return null;
16307
16466
  let skillMd = "";
16308
- const skillMdPath = join20(sourcePath, "SKILL.md");
16309
- if (existsSync11(skillMdPath)) {
16467
+ const skillMdPath = join21(sourcePath, "SKILL.md");
16468
+ if (existsSync12(skillMdPath)) {
16310
16469
  skillMd = readFileSync15(skillMdPath, "utf-8");
16311
16470
  } else if (generateSkillMd) {
16312
16471
  skillMd = generateSkillMd(name) ?? "";
@@ -16379,21 +16538,21 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
16379
16538
  const base = projectDir || process.cwd();
16380
16539
  switch (agent) {
16381
16540
  case "pi":
16382
- return scope === "project" ? join20(base, ".pi", "skills") : join20(homedir4(), ".pi", "agent", "skills");
16541
+ return scope === "project" ? join21(base, ".pi", "skills") : join21(homedir4(), ".pi", "agent", "skills");
16383
16542
  case "opencode":
16384
- return scope === "project" ? join20(base, ".opencode", "skills") : join20(homedir4(), ".config", "opencode", "skills");
16543
+ return scope === "project" ? join21(base, ".opencode", "skills") : join21(homedir4(), ".config", "opencode", "skills");
16385
16544
  default:
16386
- return scope === "project" ? join20(base, `.${agent}`, "skills") : join20(homedir4(), `.${agent}`, "skills");
16545
+ return scope === "project" ? join21(base, `.${agent}`, "skills") : join21(homedir4(), `.${agent}`, "skills");
16387
16546
  }
16388
16547
  }
16389
16548
  function getAgentSkillPath(name, agent, scope = "global", projectDir) {
16390
16549
  const skillName = normalizeSkillName(getCanonicalSkillName(name));
16391
- return join20(getAgentSkillsDir(agent, scope, projectDir), skillName);
16550
+ return join21(getAgentSkillsDir(agent, scope, projectDir), skillName);
16392
16551
  }
16393
16552
  function installSkillForAgent(name, options, generateSkillMd) {
16394
16553
  assertNativeExportAllowed();
16395
16554
  const canonicalName = getCanonicalSkillName(name);
16396
- if (!existsSync11(getSkillPath(name))) {
16555
+ if (!existsSync12(getSkillPath(name))) {
16397
16556
  return { skill: canonicalName, success: false, error: `Skill '${name}' not found` };
16398
16557
  }
16399
16558
  const scope = options.scope ?? "global";
@@ -16424,8 +16583,8 @@ function removeSkillForAgent(name, options) {
16424
16583
  }
16425
16584
  function resolveAgentSkillMd(name, generateSkillMd) {
16426
16585
  const sourcePath = getSkillPath(name);
16427
- const skillMdPath = join20(sourcePath, "SKILL.md");
16428
- if (existsSync11(skillMdPath))
16586
+ const skillMdPath = join21(sourcePath, "SKILL.md");
16587
+ if (existsSync12(skillMdPath))
16429
16588
  return readFileSync15(skillMdPath, "utf-8");
16430
16589
  if (generateSkillMd)
16431
16590
  return generateSkillMd(name);
@@ -16444,7 +16603,7 @@ function warnMissingDependencies(name, targetDir) {
16444
16603
  }
16445
16604
  function generateMinimalSkillMd(name) {
16446
16605
  const sourcePath = getSkillPath(name);
16447
- if (!existsSync11(sourcePath))
16606
+ if (!existsSync12(sourcePath))
16448
16607
  return null;
16449
16608
  const canonicalName = getCanonicalSkillName(name);
16450
16609
  const meta = getSkill(canonicalName);
@@ -16459,7 +16618,7 @@ function generateMinimalSkillMd(name) {
16459
16618
  "---",
16460
16619
  ""
16461
16620
  ].filter(Boolean);
16462
- const fallbackDoc = readFileIfExists(join20(sourcePath, "README.md")) || readFileIfExists(join20(sourcePath, "CLAUDE.md"));
16621
+ const fallbackDoc = readFileIfExists(join21(sourcePath, "README.md")) || readFileIfExists(join21(sourcePath, "CLAUDE.md"));
16463
16622
  if (fallbackDoc)
16464
16623
  return `${frontmatter.join(`
16465
16624
  `)}${fallbackDoc.trim()}
@@ -16478,8 +16637,8 @@ skills run ${canonicalName}
16478
16637
  `;
16479
16638
  }
16480
16639
  function readBundledSkillVersion(name) {
16481
- const pkgPath = join20(getSkillPath(name), "package.json");
16482
- if (!existsSync11(pkgPath))
16640
+ const pkgPath = join21(getSkillPath(name), "package.json");
16641
+ if (!existsSync12(pkgPath))
16483
16642
  return "unknown";
16484
16643
  try {
16485
16644
  const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
@@ -16489,7 +16648,7 @@ function readBundledSkillVersion(name) {
16489
16648
  }
16490
16649
  }
16491
16650
  function readFileIfExists(path) {
16492
- return existsSync11(path) ? readFileSync15(path, "utf-8") : null;
16651
+ return existsSync12(path) ? readFileSync15(path, "utf-8") : null;
16493
16652
  }
16494
16653
  function loadProjectConfigCompat(targetDir) {
16495
16654
  return loadProjectConfig(targetDir);
@@ -16533,8 +16692,8 @@ function selectSkillDoc(docs, file) {
16533
16692
  function isInstructionSkillDir(skillPath, meta) {
16534
16693
  if (meta?.kind === "instruction")
16535
16694
  return true;
16536
- const skillMdPath = join21(skillPath, "SKILL.md");
16537
- if (!existsSync12(skillMdPath))
16695
+ const skillMdPath = join23(skillPath, "SKILL.md");
16696
+ if (!existsSync13(skillMdPath))
16538
16697
  return false;
16539
16698
  try {
16540
16699
  return parseSkillFrontmatter(readFileSync16(skillMdPath, "utf-8"))?.kind === "instruction";
@@ -16560,12 +16719,12 @@ var HOSTED_PROVIDER_ENV_PREFIXES = [
16560
16719
  ];
16561
16720
  function getSkillDocs(name) {
16562
16721
  const skillPath = getSkillPath(name);
16563
- if (!existsSync12(skillPath))
16722
+ if (!existsSync13(skillPath))
16564
16723
  return null;
16565
16724
  return {
16566
- skillMd: readIfExists(join21(skillPath, "SKILL.md")),
16567
- readme: readIfExists(join21(skillPath, "README.md")),
16568
- claudeMd: readIfExists(join21(skillPath, "CLAUDE.md"))
16725
+ skillMd: readIfExists(join23(skillPath, "SKILL.md")),
16726
+ readme: readIfExists(join23(skillPath, "README.md")),
16727
+ claudeMd: readIfExists(join23(skillPath, "CLAUDE.md"))
16569
16728
  };
16570
16729
  }
16571
16730
  function getSkillBestDoc(name, file) {
@@ -16577,18 +16736,18 @@ function getSkillBestDoc(name, file) {
16577
16736
  }
16578
16737
  function getSkillRequirements(name) {
16579
16738
  const skillPath = getSkillPath(name);
16580
- if (!existsSync12(skillPath))
16739
+ if (!existsSync13(skillPath))
16581
16740
  return null;
16582
16741
  const texts = [];
16583
16742
  for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
16584
- const content = readIfExists(join21(skillPath, file));
16743
+ const content = readIfExists(join23(skillPath, file));
16585
16744
  if (content)
16586
16745
  texts.push(content);
16587
16746
  }
16588
16747
  const meta = getSkill(name);
16589
16748
  let dependencies = {};
16590
16749
  try {
16591
- dependencies = JSON.parse(readFileSync16(join21(skillPath, "package.json"), "utf8")).dependencies || {};
16750
+ dependencies = JSON.parse(readFileSync16(join23(skillPath, "package.json"), "utf8")).dependencies || {};
16592
16751
  } catch {}
16593
16752
  return getSkillRequirementsFromContent(name, texts, dependencies, meta);
16594
16753
  }
@@ -16641,7 +16800,7 @@ async function runSkill(name, args, options = {}) {
16641
16800
  const meta = getSkill(name);
16642
16801
  const canonicalName = meta?.name ?? name;
16643
16802
  const skillPath = getSkillPath(canonicalName);
16644
- if (!existsSync12(skillPath)) {
16803
+ if (!existsSync13(skillPath)) {
16645
16804
  return { exitCode: 1, error: `Skill '${name}' not found` };
16646
16805
  }
16647
16806
  if (isInstructionSkillDir(skillPath, meta)) {
@@ -16650,8 +16809,8 @@ async function runSkill(name, args, options = {}) {
16650
16809
  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'.`
16651
16810
  };
16652
16811
  }
16653
- const pkgPath = join21(skillPath, "package.json");
16654
- if (!existsSync12(pkgPath)) {
16812
+ const pkgPath = join23(skillPath, "package.json");
16813
+ if (!existsSync13(pkgPath)) {
16655
16814
  return { exitCode: 1, error: `No package.json in skill '${name}'` };
16656
16815
  }
16657
16816
  let entryPoint2;
@@ -16670,12 +16829,12 @@ async function runSkill(name, args, options = {}) {
16670
16829
  } catch {
16671
16830
  return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
16672
16831
  }
16673
- const entryPath = join21(skillPath, entryPoint2);
16674
- if (!existsSync12(entryPath)) {
16832
+ const entryPath = join23(skillPath, entryPoint2);
16833
+ if (!existsSync13(entryPath)) {
16675
16834
  return { exitCode: 1, error: `Entry point '${entryPoint2}' not found in skill '${name}'` };
16676
16835
  }
16677
16836
  const env = { ...process.env, ...options.env };
16678
- if (!existsSync12(join21(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
16837
+ if (!existsSync13(join23(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
16679
16838
  const failure = await prepareSkillDependencies(skillPath, env, options.preparationTimeoutMs);
16680
16839
  if (failure)
16681
16840
  return failure;
@@ -16744,7 +16903,7 @@ function generateSkillMd(name) {
16744
16903
  if (!meta)
16745
16904
  return null;
16746
16905
  const skillPath = getSkillPath(name);
16747
- if (!existsSync12(skillPath))
16906
+ if (!existsSync13(skillPath))
16748
16907
  return null;
16749
16908
  const frontmatter = [
16750
16909
  "---",
@@ -16753,11 +16912,11 @@ function generateSkillMd(name) {
16753
16912
  "---"
16754
16913
  ].join(`
16755
16914
  `);
16756
- const readme = readIfExists(join21(skillPath, "README.md"));
16757
- const claudeMd = readIfExists(join21(skillPath, "CLAUDE.md"));
16915
+ const readme = readIfExists(join23(skillPath, "README.md"));
16916
+ const claudeMd = readIfExists(join23(skillPath, "CLAUDE.md"));
16758
16917
  let cliCommand = null;
16759
- const pkgPath = join21(skillPath, "package.json");
16760
- if (existsSync12(pkgPath)) {
16918
+ const pkgPath = join23(skillPath, "package.json");
16919
+ if (existsSync13(pkgPath)) {
16761
16920
  try {
16762
16921
  const pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
16763
16922
  if (pkg.bin) {
@@ -16834,7 +16993,7 @@ function extractEnvVars(text2) {
16834
16993
  }
16835
16994
  function readIfExists(path) {
16836
16995
  try {
16837
- if (existsSync12(path)) {
16996
+ if (existsSync13(path)) {
16838
16997
  return readFileSync16(path, "utf-8");
16839
16998
  }
16840
16999
  } catch {}
@@ -16901,6 +17060,8 @@ async function syncSelectionProfile(profileId, options = {}) {
16901
17060
  async function resolveSelectionContext(profileId, options = {}) {
16902
17061
  const sessionState = options.sessionId ? readSkillSessionSnapshotIfExists(options.sessionId, options) : null;
16903
17062
  const session = sessionState?.receipt ?? null;
17063
+ if (options.nativeParentSessionId !== undefined && session && (session.parent?.sessionId ?? null) !== options.nativeParentSessionId)
17064
+ throw new SkillSelectionError("SESSION_PARENT_MISMATCH", "The native session id is already bound to different parent custody.");
16904
17065
  const parentState = !session && options.parentSessionId ? readSkillSessionSnapshotIfExists(options.parentSessionId, options) : null;
16905
17066
  if (!session && options.parentSessionId && !parentState) {
16906
17067
  throw new SkillSelectionError("SESSION_PARENT_NOT_FOUND", "A child Skills session requires an existing parent receipt so its inherited pin can be bound exactly.");
@@ -17160,15 +17321,15 @@ function buildPluginProjection(entries) {
17160
17321
 
17161
17322
  // src/lib/plugin-projection-store.ts
17162
17323
  import { createHash as createHash14, randomUUID as randomUUID3 } from "crypto";
17163
- import { constants as constants8, closeSync as closeSync9, fchmodSync, fstatSync as fstatSync9, fsyncSync as fsyncSync3, linkSync as linkSync2, lstatSync as lstatSync17, mkdirSync as mkdirSync8, openSync as openSync9, opendirSync as opendirSync4, readSync as readSync7, renameSync as renameSync4, rmdirSync as rmdirSync3, rmSync as rmSync3, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
17164
- import { dirname as dirname13, isAbsolute as isAbsolute12, join as join23, parse as parse5, resolve as resolve11 } from "path";
17324
+ import { constants as constants8, closeSync as closeSync9, fchmodSync, fstatSync as fstatSync9, fsyncSync as fsyncSync3, linkSync as linkSync2, lstatSync as lstatSync18, mkdirSync as mkdirSync8, openSync as openSync9, opendirSync as opendirSync4, readSync as readSync7, renameSync as renameSync4, rmdirSync as rmdirSync3, rmSync as rmSync3, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
17325
+ import { dirname as dirname13, isAbsolute as isAbsolute12, join as join25, parse as parse5, resolve as resolve12 } from "path";
17165
17326
  var READ_FLAGS = constants8.O_RDONLY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK;
17166
17327
  var WRITE_FLAGS = constants8.O_WRONLY | constants8.O_CREAT | constants8.O_EXCL | constants8.O_NOFOLLOW | constants8.O_NONBLOCK;
17167
17328
  var uid = () => typeof process.getuid === "function" ? BigInt(process.getuid()) : undefined;
17168
17329
  var missing = (error) => Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
17169
17330
  function stat(path) {
17170
17331
  try {
17171
- return lstatSync17(path, { bigint: true });
17332
+ return lstatSync18(path, { bigint: true });
17172
17333
  } catch (error) {
17173
17334
  if (missing(error))
17174
17335
  return null;
@@ -17176,7 +17337,7 @@ function stat(path) {
17176
17337
  }
17177
17338
  }
17178
17339
  function canonical5(path) {
17179
- pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute12(path) && resolve11(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
17340
+ pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute12(path) && resolve12(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
17180
17341
  }
17181
17342
  function owner(stats, system = false) {
17182
17343
  const current = uid();
@@ -17191,7 +17352,7 @@ function ancestors(path, create = false) {
17191
17352
  let current = filesystemRoot;
17192
17353
  for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
17193
17354
  if (segment)
17194
- current = join23(current, segment);
17355
+ current = join25(current, segment);
17195
17356
  let currentStat = stat(current);
17196
17357
  if (!currentStat && create) {
17197
17358
  try {
@@ -17306,7 +17467,7 @@ function snapshotPluginTree(root, options = {}) {
17306
17467
  pluginNeed(++visited <= PLUGIN_PROJECTION_LIMITS.files * 50, "Plugin tree membership exceeds its limit");
17307
17468
  const path = relative6 ? `${relative6}/${name}` : name;
17308
17469
  pluginNeed(new TextEncoder().encode(path).byteLength <= 100 && !/[\\:\x00-\x1f\x7f]/u.test(path), "Plugin entry path exceeds its limit or is unsafe");
17309
- const absolute = join23(directory, name), entryStat = stat(absolute);
17470
+ const absolute = join25(directory, name), entryStat = stat(absolute);
17310
17471
  pluginNeed(entryStat, "Plugin tree member disappeared");
17311
17472
  if (relative6 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
17312
17473
  const bytes2 = readBytes(absolute, 32, "native-pin");
@@ -17323,7 +17484,7 @@ function snapshotPluginTree(root, options = {}) {
17323
17484
  directories.push({ path: absolute, stat: entryStat, names: pins });
17324
17485
  for (const pin of pins) {
17325
17486
  pluginNeed(/^[1-9][0-9]{0,9}$/.test(pin) && Number(pin) <= 2147483647, "Unrecognized native plugin pin name");
17326
- const pinPath = join23(absolute, pin), pinStat = stat(pinPath);
17487
+ const pinPath = join25(absolute, pin), pinStat = stat(pinPath);
17327
17488
  pluginNeed(pinStat, "Native plugin pin disappeared");
17328
17489
  const bytes2 = readBytes(pinPath, 4096, "native-pin");
17329
17490
  let value;
@@ -17421,7 +17582,7 @@ function materializePluginTree(root, entries) {
17421
17582
  mkdirSync8(staging, { mode: 448 });
17422
17583
  staged = stat(staging);
17423
17584
  for (const entry of entries) {
17424
- const path = join23(staging, entry.path);
17585
+ const path = join25(staging, entry.path);
17425
17586
  ancestors(path, true);
17426
17587
  writeExclusive(path, entry.bytes, entry.mode);
17427
17588
  }
@@ -17548,7 +17709,7 @@ function describeEntries(entries) {
17548
17709
 
17549
17710
  // src/lib/plugin-admission.ts
17550
17711
  function pluginAdmissionRoot() {
17551
- return join25(homedir5(), ".hasna", "skills", "plugin-admission");
17712
+ return join26(homedir5(), ".hasna", "skills", "plugin-admission");
17552
17713
  }
17553
17714
  function validatePluginTarget(value) {
17554
17715
  pluginKeys(value, ["schemaVersion", "pluginId", "registrations", "native", "resolver"]);
@@ -17559,7 +17720,7 @@ function validatePluginTarget(value) {
17559
17720
  for (const registration of value.registrations) {
17560
17721
  pluginKeys(registration, ["scope", "projectPath"]);
17561
17722
  pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
17562
- pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute13(registration.projectPath) && resolve12(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
17723
+ pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute13(registration.projectPath) && resolve13(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
17563
17724
  const key = JSON.stringify([registration.scope, registration.projectPath]);
17564
17725
  pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
17565
17726
  scopes.add(key);
@@ -17567,7 +17728,7 @@ function validatePluginTarget(value) {
17567
17728
  for (const key of ["native", "resolver"]) {
17568
17729
  pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
17569
17730
  pluginText(value[key].executable);
17570
- pluginNeed(isAbsolute13(value[key].executable) && resolve12(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
17731
+ pluginNeed(isAbsolute13(value[key].executable) && resolve13(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
17571
17732
  pluginDigest(value[key].digest);
17572
17733
  }
17573
17734
  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)");
@@ -17719,17 +17880,17 @@ function pluginResolverCommand(binding) {
17719
17880
  }
17720
17881
  function root(options) {
17721
17882
  const path = options.storeRoot ?? pluginAdmissionRoot();
17722
- pluginNeed(isAbsolute13(path) && resolve12(path) === path, "Invalid plugin admission store root");
17883
+ pluginNeed(isAbsolute13(path) && resolve13(path) === path, "Invalid plugin admission store root");
17723
17884
  return path;
17724
17885
  }
17725
17886
  function pluginBindingPath(storeRoot, id) {
17726
17887
  pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
17727
- return join25(storeRoot, "bindings", `${id}.json`);
17888
+ return join26(storeRoot, "bindings", `${id}.json`);
17728
17889
  }
17729
17890
  function pluginReceiptPath(storeRoot, id, digest) {
17730
17891
  pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
17731
17892
  pluginDigest(digest);
17732
- return join25(storeRoot, "receipts", id, `${digest.slice(7)}.json`);
17893
+ return join26(storeRoot, "receipts", id, `${digest.slice(7)}.json`);
17733
17894
  }
17734
17895
  function readPluginBinding(storeRoot, id) {
17735
17896
  const value = readPluginJson(pluginBindingPath(storeRoot, id));
@@ -17749,7 +17910,7 @@ function readPluginAdmissionReceipt(storeRoot, id, digest) {
17749
17910
  pluginNeed(receipt.plan.bindingId === id && receipt.plan.planDigest === digest, "Plugin receipt identity differs from its filename");
17750
17911
  const binding = readPluginBinding(storeRoot, id);
17751
17912
  pluginNeed(canonicalJson(binding) === canonicalJson(receipt.plan.binding) && receipt.plan.sourceCommand === pluginResolverCommand(binding), "Plugin receipt binding changed");
17752
- pluginNeed(receipt.materializedPath === join25(storeRoot, "objects", id, digest.slice(7)), "Plugin receipt points outside its immutable materialization");
17913
+ pluginNeed(receipt.materializedPath === join26(storeRoot, "objects", id, digest.slice(7)), "Plugin receipt points outside its immutable materialization");
17753
17914
  pluginText(receipt.admittedAt, 64);
17754
17915
  pluginNeed(Number.isFinite(Date.parse(receipt.admittedAt)), "Invalid plugin admission time");
17755
17916
  return receipt;
@@ -17890,7 +18051,7 @@ async function admitPlugin(spec, profileId, target, approvedDigest, approvedEvid
17890
18051
  const { plan, projection } = await candidate(spec, profileId, target, options);
17891
18052
  pluginNeed(plan.planDigest === approvedDigest, "The plugin plan changed since review; obtain and review a new plan");
17892
18053
  pluginNeed(plan.evidenceDigest === approvedEvidenceDigest, "The plugin routing evidence changed since review; obtain and review a new plan");
17893
- const store = root(options), materializedPath = join25(store, "objects", plan.bindingId, plan.planDigest.slice(7));
18054
+ const store = root(options), materializedPath = join26(store, "objects", plan.bindingId, plan.planDigest.slice(7));
17894
18055
  materializePluginTree(materializedPath, projection.files);
17895
18056
  writePluginJsonImmutable(pluginBindingPath(store, plan.bindingId), plan.binding);
17896
18057
  const path = pluginReceiptPath(store, plan.bindingId, plan.planDigest), existing = readPluginJson(path);
@@ -17924,21 +18085,21 @@ function validateManagedPluginWitnesses(value) {
17924
18085
  pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
17925
18086
  seen.add(item.bindingId);
17926
18087
  pluginText(item.storeRoot);
17927
- pluginNeed(isAbsolute14(item.storeRoot) && resolve13(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
18088
+ pluginNeed(isAbsolute14(item.storeRoot) && resolve14(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
17928
18089
  }
17929
18090
  }
17930
18091
  function safe3(path) {
17931
18092
  pluginText(path);
17932
- pluginNeed(isAbsolute14(path) && resolve13(path) === path, "Invalid plugin registry path");
18093
+ pluginNeed(isAbsolute14(path) && resolve14(path) === path, "Invalid plugin registry path");
17933
18094
  for (let at = path;; at = dirname14(at)) {
17934
- pluginNeed(!lstatSync18(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
18095
+ pluginNeed(!lstatSync19(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
17935
18096
  if (at === dirname14(at))
17936
18097
  break;
17937
18098
  }
17938
18099
  }
17939
18100
  function readRegistry(path) {
17940
18101
  safe3(path);
17941
- const initial = lstatSync18(path);
18102
+ const initial = lstatSync19(path);
17942
18103
  pluginNeed(initial.isFile() && initial.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
17943
18104
  const fd = openSync10(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
17944
18105
  try {
@@ -17952,7 +18113,7 @@ function readRegistry(path) {
17952
18113
  break;
17953
18114
  length += count;
17954
18115
  }
17955
- const after = fstatSync10(fd), current = lstatSync18(path);
18116
+ const after = fstatSync10(fd), current = lstatSync19(path);
17956
18117
  safe3(path);
17957
18118
  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");
17958
18119
  let value;
@@ -17982,7 +18143,7 @@ function hashManagedPluginRegistry(path, managed) {
17982
18143
  seen.add(target.pluginId);
17983
18144
  const rows = plugins[target.pluginId];
17984
18145
  pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
17985
- const [name, market] = target.pluginId.split("@"), cacheRoot = join26(dirname14(path), "cache", market, name);
18146
+ const [name, market] = target.pluginId.split("@"), cacheRoot = join27(dirname14(path), "cache", market, name);
17986
18147
  const scopes = new Set, approvals = new Map, currentFiles = new Map;
17987
18148
  plugins[target.pluginId] = rows.map((row) => {
17988
18149
  pluginNeed(pluginObject(row), "Invalid managed plugin registration");
@@ -17995,7 +18156,7 @@ function hashManagedPluginRegistry(path, managed) {
17995
18156
  pluginText(row.sourceProducerPath);
17996
18157
  pluginText(row.lastUpdated, 64);
17997
18158
  pluginNeed(Number.isFinite(Date.parse(row.lastUpdated)), "Invalid managed plugin update timestamp");
17998
- pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join26(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
18159
+ pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join27(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
17999
18160
  const approval = (producer) => {
18000
18161
  pluginText(producer);
18001
18162
  const digest = `sha256:${basename7(producer)}`;
@@ -18025,7 +18186,7 @@ function hashManagedPluginRegistry(path, managed) {
18025
18186
  return Object.fromEntries(Object.entries(row).filter(([key]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key)));
18026
18187
  });
18027
18188
  safe3(cacheRoot);
18028
- const before = lstatSync18(cacheRoot);
18189
+ const before = lstatSync19(cacheRoot);
18029
18190
  pluginNeed(before.isDirectory(), "Invalid managed plugin cache root");
18030
18191
  const directory = opendirSync5(cacheRoot), names = [];
18031
18192
  try {
@@ -18038,17 +18199,17 @@ function hashManagedPluginRegistry(path, managed) {
18038
18199
  directory.closeSync();
18039
18200
  }
18040
18201
  for (const version of names.sort()) {
18041
- const files = pluginFileWitnesses(snapshotPluginTree(join26(cacheRoot, version), { nativeRuntime: `claude-${target.native.version}` }));
18202
+ const files = pluginFileWitnesses(snapshotPluginTree(join27(cacheRoot, version), { nativeRuntime: `claude-${target.native.version}` }));
18042
18203
  verifiedBytes += files.reduce((total, file) => total + file.size, 0);
18043
18204
  pluginNeed(verifiedBytes <= 256 * 1024 * 1024, "Managed plugin verification exceeds its aggregate byte budget");
18044
18205
  const serialized = JSON.stringify(files);
18045
- const expected = currentFiles.get(join26(cacheRoot, version));
18206
+ const expected = currentFiles.get(join27(cacheRoot, version));
18046
18207
  pluginNeed(expected === undefined || serialized === expected, "Current native cache differs from its exact registered producer receipt");
18047
18208
  pluginNeed([...approvals.values()].some((receipt) => nativeVersionMatches(version, receipt) && JSON.stringify(receipt.plan.files) === serialized), "A retained native plugin cache version differs from every approved projection");
18048
18209
  }
18049
18210
  for (const row of rows)
18050
18211
  pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
18051
- const after = lstatSync18(cacheRoot);
18212
+ const after = lstatSync19(cacheRoot);
18052
18213
  safe3(cacheRoot);
18053
18214
  pluginNeed(before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs, "Managed cache version membership changed during verification");
18054
18215
  }
@@ -18061,21 +18222,21 @@ function captureManagedPluginRegistry(path, managedPlugins) {
18061
18222
 
18062
18223
  // src/lib/claude-marketplace-registry.ts
18063
18224
  import { createHash as createHash15 } from "crypto";
18064
- import { closeSync as closeSync11, constants as constants10, fstatSync as fstatSync11, lstatSync as lstatSync19, openSync as openSync11, readSync as readSync9 } from "fs";
18065
- import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve14 } from "path";
18225
+ import { closeSync as closeSync11, constants as constants10, fstatSync as fstatSync11, lstatSync as lstatSync20, openSync as openSync11, readSync as readSync9 } from "fs";
18226
+ import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve15 } from "path";
18066
18227
  var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
18067
18228
  function need5(value, reason) {
18068
18229
  if (!value)
18069
18230
  throw new Error(`Claude marketplace registry ${reason}`);
18070
18231
  }
18071
18232
  function absolutePath3(value) {
18072
- need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve14(value) === value, "requires a normalized absolute path");
18233
+ need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve15(value) === value, "requires a normalized absolute path");
18073
18234
  }
18074
18235
  var sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs;
18075
18236
  function parents2(path) {
18076
18237
  const result = [];
18077
18238
  for (let at = dirname15(path);; at = dirname15(at)) {
18078
- const stat2 = lstatSync19(at, { bigint: true });
18239
+ const stat2 = lstatSync20(at, { bigint: true });
18079
18240
  need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
18080
18241
  result.push([at, stat2]);
18081
18242
  if (at === dirname15(at))
@@ -18086,7 +18247,7 @@ function readRegistry2(path, budget) {
18086
18247
  absolutePath3(path);
18087
18248
  need5(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
18088
18249
  need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
18089
- const ancestors2 = parents2(path), initial = lstatSync19(path, { bigint: true });
18250
+ const ancestors2 = parents2(path), initial = lstatSync20(path, { bigint: true });
18090
18251
  need5(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
18091
18252
  need5(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
18092
18253
  const fd = openSync11(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
@@ -18101,10 +18262,10 @@ function readRegistry2(path, budget) {
18101
18262
  break;
18102
18263
  length += count;
18103
18264
  }
18104
- const after = fstatSync11(fd, { bigint: true }), current = lstatSync19(path, { bigint: true });
18265
+ const after = fstatSync11(fd, { bigint: true }), current = lstatSync20(path, { bigint: true });
18105
18266
  need5(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
18106
18267
  for (const [ancestor, before] of ancestors2) {
18107
- const now = lstatSync19(ancestor, { bigint: true });
18268
+ const now = lstatSync20(ancestor, { bigint: true });
18108
18269
  need5(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
18109
18270
  }
18110
18271
  budget.remaining -= length;
@@ -18244,7 +18405,7 @@ function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 10
18244
18405
  import { createHash as createHash17 } from "crypto";
18245
18406
 
18246
18407
  // src/lib/codex-hook-trust-files.ts
18247
- import { closeSync as closeSync12, constants as constants11, fstatSync as fstatSync12, fsyncSync as fsyncSync4, lstatSync as lstatSync20, openSync as openSync12, readSync as readSync10, writeFileSync as writeFileSync7 } from "fs";
18408
+ import { closeSync as closeSync12, constants as constants11, fstatSync as fstatSync12, fsyncSync as fsyncSync4, lstatSync as lstatSync21, openSync as openSync12, readSync as readSync10, writeFileSync as writeFileSync7 } from "fs";
18248
18409
  import { createHash as createHash16 } from "crypto";
18249
18410
  import { dirname as dirname16 } from "path";
18250
18411
  function need6(value, code) {
@@ -18254,7 +18415,7 @@ function need6(value, code) {
18254
18415
  var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
18255
18416
  function safeParents(file) {
18256
18417
  for (let p = dirname16(file);; p = dirname16(p)) {
18257
- const s = lstatSync20(p);
18418
+ const s = lstatSync21(p);
18258
18419
  need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
18259
18420
  need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
18260
18421
  if (dirname16(p) === p)
@@ -18264,7 +18425,7 @@ function safeParents(file) {
18264
18425
  function snapshot(file, privateFile = false, options = {}) {
18265
18426
  const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
18266
18427
  safeParents(file);
18267
- const initial = lstatSync20(file, { bigint: true });
18428
+ const initial = lstatSync21(file, { bigint: true });
18268
18429
  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");
18269
18430
  need6(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
18270
18431
  const fd = openSync12(file, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
@@ -18279,7 +18440,7 @@ function snapshot(file, privateFile = false, options = {}) {
18279
18440
  break;
18280
18441
  length += n2;
18281
18442
  }
18282
- need6(length === Number(before.size) && sameStat(before, fstatSync12(fd, { bigint: true })) && sameStat(before, lstatSync20(file, { bigint: true })), "INPUT_CHANGED");
18443
+ need6(length === Number(before.size) && sameStat(before, fstatSync12(fd, { bigint: true })) && sameStat(before, lstatSync21(file, { bigint: true })), "INPUT_CHANGED");
18283
18444
  const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
18284
18445
  return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash16("sha256").update(content).digest("hex") };
18285
18446
  } finally {
@@ -18331,7 +18492,7 @@ function safe4(path) {
18331
18492
  if (!isAbsolute16(path) || path.includes("\x00"))
18332
18493
  throw new Error("Expected an absolute native discovery path");
18333
18494
  for (let cursor = path;; cursor = dirname17(cursor)) {
18334
- if (lstatSync21(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
18495
+ if (lstatSync22(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
18335
18496
  throw new Error(`Refusing symlink native discovery input: ${cursor}`);
18336
18497
  if (dirname17(cursor) === cursor)
18337
18498
  break;
@@ -18341,7 +18502,7 @@ function read2(path, changes) {
18341
18502
  safe4(path);
18342
18503
  if (changes?.has(path))
18343
18504
  return changes.get(path);
18344
- const stat2 = lstatSync21(path, { throwIfNoEntry: false });
18505
+ const stat2 = lstatSync22(path, { throwIfNoEntry: false });
18345
18506
  if (!stat2)
18346
18507
  return null;
18347
18508
  if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
@@ -18452,12 +18613,12 @@ function codexInstallationRoots(binding) {
18452
18613
  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)
18453
18614
  throw new Error("Invalid native installation input proof");
18454
18615
  const cache = dirname17(dirname17(proof.plugins[0].pluginParent));
18455
- const config = join27(dirname17(dirname17(cache)), "config.toml"), home = dirname17(dirname17(dirname17(cache)));
18616
+ const config = join28(dirname17(dirname17(cache)), "config.toml"), home = dirname17(dirname17(dirname17(cache)));
18456
18617
  const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
18457
- const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join27(home, path));
18618
+ const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join28(home, path));
18458
18619
  if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep6) || input.sourceRoot.startsWith(root2 + sep6)) || binding.sources.some((source) => basename9(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep6)))))
18459
18620
  throw new Error("Native installation input overlaps configuration or loading roots");
18460
- if (proof.plugins.some((input) => dirname17(dirname17(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join27(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
18621
+ if (proof.plugins.some((input) => dirname17(dirname17(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join28(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
18461
18622
  throw new Error("Missing native installation input source witness");
18462
18623
  return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
18463
18624
  const text2 = read2(path);
@@ -18499,19 +18660,19 @@ function captureDiscoveryPathSources(paths) {
18499
18660
  const budget = discoveryByteBudget();
18500
18661
  return paths.map((path) => ({ path, hashMode: "path-bytes", sha256: hashDiscoveryPathFile(path, budget) }));
18501
18662
  }
18502
- function assertProjectDiscovery(agent, directories, home, canonical6 = resolve15, reviewed) {
18663
+ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve16, reviewed) {
18503
18664
  const homeConfigPath = canonical6(agentDiscoveryConfigPath(home, agent));
18504
18665
  for (const directory of directories) {
18505
- const isHome = resolve15(directory) === resolve15(home);
18666
+ const isHome = resolve16(directory) === resolve16(home);
18506
18667
  if (agent === "hermes") {
18507
18668
  assertHermesEnvironment(home);
18508
18669
  continue;
18509
18670
  }
18510
- if (isHome && agent !== "claude")
18671
+ if (isHome && agent !== "claude" && agent !== "sumi")
18511
18672
  continue;
18512
- const paths = agent === "claude" ? [...isHome ? [] : [".claude/settings.json"], ".claude/settings.local.json"] : agent === "codex" ? [".codex/config.toml"] : agent === "gemini" ? [".gemini/settings.json"] : agent === "opencode" ? ["opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc"] : [".cursor/hooks.json"];
18673
+ const paths = agent === "claude" ? [...isHome ? [] : [".claude/settings.json"], ".claude/settings.local.json"] : agent === "codex" ? [".codex/config.toml"] : agent === "gemini" ? [".gemini/settings.json"] : agent === "opencode" ? ["opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc"] : agent === "sumi" ? ["sumi.json", "sumi.jsonc", ".sumi/sumi.json", ".sumi/sumi.jsonc"] : [".cursor/hooks.json"];
18513
18674
  for (const suffix of paths) {
18514
- const path = canonical6(join27(directory, suffix)), raw = read2(path);
18675
+ const path = canonical6(join28(directory, suffix)), raw = read2(path);
18515
18676
  if (raw === null)
18516
18677
  continue;
18517
18678
  const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
@@ -18520,7 +18681,7 @@ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve15
18520
18681
  if (suffix.endsWith(".jsonc"))
18521
18682
  throw new Error(`NATIVE_SKILL_DRIFT: project JSONC discovery configuration requires review: ${path}`);
18522
18683
  const config = parseConfig(raw, path, suffix.endsWith(".toml"));
18523
- const keys = agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces", "skillOverrides"] : agent === "codex" ? ["plugins", "marketplaces", "skills"] : agent === "gemini" ? ["skills", "extensions"] : agent === "opencode" ? ["plugin", "skills"] : ["hooks"];
18684
+ const keys = agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces", "skillOverrides"] : agent === "codex" ? ["plugins", "marketplaces", "skills"] : agent === "gemini" ? ["skills", "extensions"] : agent === "opencode" ? ["plugin", "skills"] : agent === "sumi" ? ["plugin", "plugins", "skills", "permissions"] : ["hooks"];
18524
18685
  let admittedPlugins = false;
18525
18686
  if (agent === "claude" && reviewed?.agent === agent && reviewed.method === "reviewed" && config.enabledPlugins && typeof config.enabledPlugins === "object" && !Array.isArray(config.enabledPlugins)) {
18526
18687
  const exact = reviewed.sources.find((source) => source.path === path && source.format === undefined && source.fields === undefined && (source.hashMode === undefined || source.hashMode === "bytes"));
@@ -18533,19 +18694,28 @@ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve15
18533
18694
  if (keys.some((key) => config[key] !== undefined && !(key === "enabledPlugins" && admittedPlugins)) || config.disableAllHooks === true || config.disableBundledSkills === false || config.hooksConfig?.enabled === false || config.permission?.skill !== undefined || config.permissions?.deny?.some((rule) => typeof rule === "string" && /^Skill(?:\(|$)/.test(rule)))
18534
18695
  throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
18535
18696
  }
18697
+ if (agent === "sumi")
18698
+ for (const name of ["plugin", "plugins"]) {
18699
+ const path = canonical6(join28(directory, ".sumi", name));
18700
+ safe4(path);
18701
+ if (lstatSync22(path, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(path).length)
18702
+ throw new Error(`NATIVE_SKILL_DRIFT: project Sumi plugins require a dedicated discovery review: ${path}`);
18703
+ }
18536
18704
  if (agent === "claude") {
18537
- const commands = canonical6(join27(directory, ".claude/commands"));
18705
+ const commands = canonical6(join28(directory, ".claude/commands"));
18538
18706
  safe4(commands);
18539
- if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length)
18707
+ if (lstatSync22(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length)
18540
18708
  throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
18541
18709
  }
18542
18710
  }
18543
18711
  }
18544
18712
  function agentDiscoveryConfigPath(home, agent) {
18545
- return join27(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
18713
+ if (agent === "sumi")
18714
+ return sumiConfigPath(home);
18715
+ return join28(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
18546
18716
  }
18547
18717
  function resolveAgentDiscovery(options) {
18548
- const canonical6 = options.canonical ?? resolve15, home = resolve15(options.home), agent = options.agent;
18718
+ const canonical6 = options.canonical ?? resolve16, home = resolve16(options.home), agent = options.agent;
18549
18719
  const sources = [], roots = new Set, builtinNames = [];
18550
18720
  const witness = (path, format, fields2) => {
18551
18721
  const source = { path: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
@@ -18556,13 +18726,49 @@ function resolveAgentDiscovery(options) {
18556
18726
  if (agent === "hermes")
18557
18727
  assertHermesEnvironment(home);
18558
18728
  const configPath = agentDiscoveryConfigPath(home, agent);
18559
- 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"]);
18729
+ 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"]);
18560
18730
  const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
18561
18731
  const unresolved = (detail) => {
18562
18732
  throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
18563
18733
  };
18734
+ if (agent === "sumi") {
18735
+ const directory = sumiConfigDirectory(home);
18736
+ if (witness(join28(directory, "sumi.jsonc")) !== null)
18737
+ unresolved("JSONC configuration requires a supported format adapter");
18738
+ for (const root2 of [directory, join28(home, ".claude"), join28(home, ".agents")])
18739
+ for (const name of ["skill", "skills"])
18740
+ roots.add(join28(root2, name));
18741
+ if (config.skills !== undefined && (!Array.isArray(config.skills) || config.skills.some((path) => typeof path !== "string")))
18742
+ unresolved("skills must be a string array");
18743
+ for (const value of config.skills ?? []) {
18744
+ if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute16(value) || value.startsWith("~/")))
18745
+ unresolved("remote or relative skill sources need a dedicated discovery adapter");
18746
+ roots.add(value.startsWith("~/") ? join28(home, value.slice(2)) : value);
18747
+ }
18748
+ for (const key of ["plugin", "plugins"])
18749
+ if (config[key] !== undefined && !Array.isArray(config[key]))
18750
+ unresolved(`${key} must be an array`);
18751
+ const plugins = [join28(directory, "plugin"), join28(directory, "plugins")];
18752
+ for (const path of plugins) {
18753
+ safe4(path);
18754
+ if (lstatSync22(path, { throwIfNoEntry: false })?.isDirectory())
18755
+ for (const name of readdirSync10(path).sort()) {
18756
+ if (name === "skills-cli.js" && path === plugins[1])
18757
+ continue;
18758
+ const target = join28(path, name);
18759
+ if (!lstatSync22(target).isFile())
18760
+ unresolved("local plugin packages need a dedicated discovery adapter");
18761
+ witness(target);
18762
+ }
18763
+ }
18764
+ for (const root2 of roots) {
18765
+ safe4(root2);
18766
+ if (lstatSync22(root2, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(root2).some((name) => name.endsWith(".md")))
18767
+ unresolved("flat markdown skills require a dedicated native migration adapter");
18768
+ }
18769
+ }
18564
18770
  if (agent === "hermes") {
18565
- const profile = witness(join27(home, ".hermes/active_profile"));
18771
+ const profile = witness(join28(home, ".hermes/active_profile"));
18566
18772
  if (profile?.trim() && profile.trim() !== "default")
18567
18773
  unresolved("a non-default profile is active");
18568
18774
  const declared = config.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
@@ -18576,7 +18782,7 @@ function resolveAgentDiscovery(options) {
18576
18782
  continue;
18577
18783
  if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
18578
18784
  unresolved("user-specific tilde expansion requires a separate discovery adapter");
18579
- const path = normalized === "~" ? home : normalized.startsWith("~/") ? join27(home, normalized.slice(2)) : resolve15(home, ".hermes", normalized);
18785
+ const path = normalized === "~" ? home : normalized.startsWith("~/") ? join28(home, normalized.slice(2)) : resolve16(home, ".hermes", normalized);
18580
18786
  safe4(path);
18581
18787
  roots.add(path);
18582
18788
  }
@@ -18585,8 +18791,8 @@ function resolveAgentDiscovery(options) {
18585
18791
  const executable = Bun.which("gemini");
18586
18792
  if (executable) {
18587
18793
  let packageRoot;
18588
- for (let directory = dirname17(realpathSync7(executable)), depth = 0;depth < 8; directory = dirname17(directory), depth++) {
18589
- const path = join27(directory, "package.json"), raw = read2(path);
18794
+ for (let directory = dirname17(realpathSync8(executable)), depth = 0;depth < 8; directory = dirname17(directory), depth++) {
18795
+ const path = join28(directory, "package.json"), raw = read2(path);
18590
18796
  if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
18591
18797
  packageRoot = directory;
18592
18798
  witness(path);
@@ -18597,12 +18803,12 @@ function resolveAgentDiscovery(options) {
18597
18803
  }
18598
18804
  if (!packageRoot)
18599
18805
  unresolved("installed Gemini package layout is not recognized");
18600
- const builtinRoot = join27(packageRoot, "bundle/builtin");
18806
+ const builtinRoot = join28(packageRoot, "bundle/builtin");
18601
18807
  safe4(builtinRoot);
18602
- if (!lstatSync21(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
18808
+ if (!lstatSync22(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
18603
18809
  unresolved("installed Gemini builtin root is missing");
18604
18810
  for (const name of readdirSync10(builtinRoot).sort()) {
18605
- const text2 = witness(join27(builtinRoot, name, "SKILL.md"));
18811
+ const text2 = witness(join28(builtinRoot, name, "SKILL.md"));
18606
18812
  const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
18607
18813
  if (!match?.[1] || builtinNames.includes(match[1]))
18608
18814
  unresolved("installed Gemini builtin name is missing or ambiguous");
@@ -18644,39 +18850,39 @@ function resolveAgentDiscovery(options) {
18644
18850
  function plugin(root2) {
18645
18851
  root2 = canonical6(root2);
18646
18852
  safe4(root2);
18647
- const manifestPath = join27(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
18853
+ const manifestPath = join28(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
18648
18854
  const raw = witness(manifestPath);
18649
18855
  if (raw === null)
18650
18856
  unresolved("plugin manifest missing");
18651
18857
  const manifest = parseConfig(raw, manifestPath);
18652
- const hooks = witness(join27(root2, "hooks/hooks.json"));
18858
+ const hooks = witness(join28(root2, "hooks/hooks.json"));
18653
18859
  if (manifest.hooks !== undefined || hooks !== null)
18654
18860
  unresolved("plugin hooks require a separate no-skill-injection review");
18655
- const commands = join27(root2, "commands");
18861
+ const commands = join28(root2, "commands");
18656
18862
  safe4(commands);
18657
- if (agent === "claude" && (manifest.commands !== undefined || lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length))
18863
+ if (agent === "claude" && (manifest.commands !== undefined || lstatSync22(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length))
18658
18864
  unresolved("legacy command discovery requires retirement or a dedicated format adapter");
18659
- const rootSkill = witness(join27(root2, "SKILL.md"));
18865
+ const rootSkill = witness(join28(root2, "SKILL.md"));
18660
18866
  if (rootSkill !== null)
18661
18867
  roots.add(root2);
18662
18868
  const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
18663
18869
  if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
18664
18870
  unresolved("unsupported plugin skill paths");
18665
18871
  if (agent === "claude")
18666
- roots.add(join27(root2, "skills"));
18872
+ roots.add(join28(root2, "skills"));
18667
18873
  for (const value of declared) {
18668
- const path = resolve15(root2, value);
18874
+ const path = resolve16(root2, value);
18669
18875
  if (path !== root2 && !path.startsWith(root2 + sep6))
18670
18876
  unresolved("plugin skill path escapes its root");
18671
18877
  roots.add(path.endsWith(`${sep6}SKILL.md`) ? dirname17(path) : path);
18672
18878
  }
18673
18879
  }
18674
18880
  if (agent === "claude") {
18675
- const registrations = witness(join27(home, ".claude/plugins/installed_plugins.json"));
18676
- const installed = registrations === null ? {} : parseConfig(registrations, join27(home, ".claude/plugins/installed_plugins.json")).plugins;
18677
- const commands = canonical6(join27(home, ".claude/commands"));
18881
+ const registrations = witness(join28(home, ".claude/plugins/installed_plugins.json"));
18882
+ const installed = registrations === null ? {} : parseConfig(registrations, join28(home, ".claude/plugins/installed_plugins.json")).plugins;
18883
+ const commands = canonical6(join28(home, ".claude/commands"));
18678
18884
  safe4(commands);
18679
- if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length)
18885
+ if (lstatSync22(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync10(commands).length)
18680
18886
  unresolved("legacy home command discovery requires a dedicated format adapter");
18681
18887
  for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
18682
18888
  if (enabled === false)
@@ -18698,16 +18904,16 @@ function resolveAgentDiscovery(options) {
18698
18904
  const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
18699
18905
  if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute16(market.source))
18700
18906
  unresolved("enabled plugin marketplace is not an explicit local source");
18701
- const catalogText = witness(join27(market.source, ".agents/plugins/marketplace.json"));
18907
+ const catalogText = witness(join28(market.source, ".agents/plugins/marketplace.json"));
18702
18908
  if (catalogText === null)
18703
18909
  unresolved("marketplace catalog missing");
18704
- const catalog = parseConfig(catalogText, join27(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
18910
+ const catalog = parseConfig(catalogText, join28(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
18705
18911
  if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
18706
18912
  unresolved("plugin catalog source is missing or ambiguous");
18707
- plugin(resolve15(market.source, matches[0].source.path));
18913
+ plugin(resolve16(market.source, matches[0].source.path));
18708
18914
  }
18709
18915
  } else if (agent === "opencode") {
18710
- if (witness(join27(home, ".config/opencode/opencode.jsonc")) !== null || witness(join27(home, ".config/opencode/config.json")) !== null)
18916
+ if (witness(join28(home, ".config/opencode/opencode.jsonc")) !== null || witness(join28(home, ".config/opencode/config.json")) !== null)
18711
18917
  unresolved("additional config layers require review");
18712
18918
  if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
18713
18919
  unresolved("external plugin or remote skill source");
@@ -18716,14 +18922,17 @@ function resolveAgentDiscovery(options) {
18716
18922
  unresolved("relative or malformed added skill root");
18717
18923
  roots.add(path);
18718
18924
  }
18719
- const localPlugins = join27(home, ".config/opencode/plugins");
18925
+ const localPlugins = join28(home, ".config/opencode/plugins");
18720
18926
  safe4(localPlugins);
18721
- if (lstatSync21(localPlugins, { throwIfNoEntry: false }) && readdirSync10(localPlugins).some((name) => name !== "skills-cli.js"))
18927
+ if (lstatSync22(localPlugins, { throwIfNoEntry: false }) && readdirSync10(localPlugins).some((name) => name !== "skills-cli.js"))
18722
18928
  unresolved("additional local plugin hooks require review");
18929
+ } else if (agent === "sumi") {
18930
+ if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical6(configPath) && source.path !== canonical6(join28(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
18931
+ unresolved("external or foreign local plugins require review");
18723
18932
  } else if (agent === "hermes") {
18724
- for (const directory of [join27(home, ".hermes/plugins"), join27(home, ".hermes/hermes-agent")]) {
18933
+ for (const directory of [join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")]) {
18725
18934
  safe4(directory);
18726
- if (lstatSync21(directory, { throwIfNoEntry: false }))
18935
+ if (lstatSync22(directory, { throwIfNoEntry: false }))
18727
18936
  unresolved("installed runtime/plugin discovery requires reviewed source bindings");
18728
18937
  }
18729
18938
  if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
@@ -18731,30 +18940,30 @@ function resolveAgentDiscovery(options) {
18731
18940
  } else if (agent === "gemini") {
18732
18941
  if (Object.keys(config.extensions ?? {}).length || config.skills?.paths?.length)
18733
18942
  unresolved("custom extension or skill paths");
18734
- const directory = join27(home, ".gemini/extensions");
18943
+ const directory = join28(home, ".gemini/extensions");
18735
18944
  safe4(directory);
18736
- if (lstatSync21(directory, { throwIfNoEntry: false }))
18945
+ if (lstatSync22(directory, { throwIfNoEntry: false }))
18737
18946
  for (const name of readdirSync10(directory)) {
18738
- const root2 = join27(directory, name);
18947
+ const root2 = join28(directory, name);
18739
18948
  safe4(root2);
18740
- if (!lstatSync21(root2)?.isDirectory())
18949
+ if (!lstatSync22(root2)?.isDirectory())
18741
18950
  continue;
18742
- const raw = witness(join27(root2, "gemini-extension.json"));
18951
+ const raw = witness(join28(root2, "gemini-extension.json"));
18743
18952
  if (raw === null)
18744
18953
  unresolved("extension registration missing");
18745
- const manifest = parseConfig(raw, join27(root2, "gemini-extension.json"));
18746
- if (manifest.hooks !== undefined || witness(join27(root2, "hooks/hooks.json")) !== null || witness(join27(root2, ".gemini-extension-install.json")) !== null)
18954
+ const manifest = parseConfig(raw, join28(root2, "gemini-extension.json"));
18955
+ if (manifest.hooks !== undefined || witness(join28(root2, "hooks/hooks.json")) !== null || witness(join28(root2, ".gemini-extension-install.json")) !== null)
18747
18956
  unresolved("extension hooks or linked registration require review");
18748
- roots.add(join27(root2, "skills"));
18957
+ roots.add(join28(root2, "skills"));
18749
18958
  }
18750
18959
  }
18751
- return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join27(home, ".hermes/plugins"), join27(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
18960
+ return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
18752
18961
  }
18753
18962
 
18754
18963
  // src/lib/authoring-path.ts
18755
18964
  var NATIVE_DISCOVERY_ROOTS = NATIVE_SKILL_ROOTS.map(([, path]) => path.split("/"));
18756
18965
  function pathParts(path) {
18757
- return resolve16(path).split(sep7).filter(Boolean);
18966
+ return resolve17(path).split(sep7).filter(Boolean);
18758
18967
  }
18759
18968
  function nativeRootMatch(path) {
18760
18969
  const parts = pathParts(path);
@@ -18768,24 +18977,24 @@ function nativeRootMatch(path) {
18768
18977
  return;
18769
18978
  }
18770
18979
  function physicalPath(path) {
18771
- let cursor = resolve16(path);
18980
+ let cursor = resolve17(path);
18772
18981
  const suffix = [];
18773
- while (!lstatSync22(cursor, { throwIfNoEntry: false })) {
18982
+ while (!lstatSync23(cursor, { throwIfNoEntry: false })) {
18774
18983
  suffix.unshift(basename10(cursor));
18775
18984
  const parent = dirname18(cursor);
18776
18985
  if (parent === cursor)
18777
- return resolve16(path);
18986
+ return resolve17(path);
18778
18987
  cursor = parent;
18779
18988
  }
18780
- return resolve16(realpathSync8(cursor), ...suffix);
18989
+ return resolve17(realpathSync9(cursor), ...suffix);
18781
18990
  }
18782
18991
  function contains(root2, path) {
18783
18992
  return path === root2 || path.startsWith(root2 + sep7);
18784
18993
  }
18785
18994
  function configuredRoots(home, explicitHome) {
18786
- const homeData = join28(home, ".hasna", "skills");
18995
+ const homeData = join29(home, ".hasna", "skills");
18787
18996
  const homePolicy = readManagedSkillPolicySnapshot(homeData);
18788
- const configuredPolicy = !explicitHome && resolve16(getDataDirReadOnly()) !== resolve16(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
18997
+ const configuredPolicy = !explicitHome && resolve17(getDataDirReadOnly()) !== resolve17(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
18789
18998
  const policy = homePolicy ?? configuredPolicy;
18790
18999
  const bridge = policy?.value.bridge;
18791
19000
  if (bridge && (typeof bridge.home !== "string" || physicalPath(bridge.home) !== physicalPath(home))) {
@@ -18814,8 +19023,8 @@ function configuredRoots(home, explicitHome) {
18814
19023
  admitBinding(binding);
18815
19024
  continue;
18816
19025
  }
18817
- const nativeHome = join28(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
18818
- if (!lstatSync22(nativeHome, { throwIfNoEntry: false }))
19026
+ const nativeHome = join29(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
19027
+ if (!lstatSync23(nativeHome, { throwIfNoEntry: false }))
18819
19028
  continue;
18820
19029
  roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
18821
19030
  }
@@ -18824,22 +19033,22 @@ function configuredRoots(home, explicitHome) {
18824
19033
  function assertPortableAuthoringPath(path, options = {}) {
18825
19034
  if (typeof path !== "string" || !path || path.includes("\x00"))
18826
19035
  throw new Error("Invalid portable authoring path");
18827
- const lexical = resolve16(path);
19036
+ const lexical = resolve17(path);
18828
19037
  const physical = physicalPath(lexical);
18829
19038
  const candidates = [lexical, physical];
18830
19039
  let native = candidates.map(nativeRootMatch).find(Boolean);
18831
- const home = resolve16(options.homeDir ?? homedir6());
18832
- const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join28(home, ...parts));
18833
- defaults.push(join28(home, ".codex/plugins/cache"), join28(home, ".claude/plugins/cache"), join28(home, ".claude/plugins/synced"), join28(home, ".gemini/extensions"));
19040
+ const home = resolve17(options.homeDir ?? homedir6());
19041
+ const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join29(home, ...parts));
19042
+ defaults.push(join29(home, ".codex/plugins/cache"), join29(home, ".claude/plugins/cache"), join29(home, ".claude/plugins/synced"), join29(home, ".gemini/extensions"));
18834
19043
  for (const root2 of defaults) {
18835
- if (candidates.some((candidate2) => contains(resolve16(root2), candidate2) || contains(physicalPath(root2), candidate2)))
19044
+ if (candidates.some((candidate2) => contains(resolve17(root2), candidate2) || contains(physicalPath(root2), candidate2)))
18836
19045
  native ??= root2;
18837
19046
  }
18838
19047
  if (native) {
18839
19048
  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.`);
18840
19049
  }
18841
19050
  for (const root2 of configuredRoots(home, options.homeDir !== undefined)) {
18842
- if (candidates.some((candidate2) => contains(resolve16(root2), candidate2) || contains(physicalPath(root2), candidate2))) {
19051
+ if (candidates.some((candidate2) => contains(resolve17(root2), candidate2) || contains(physicalPath(root2), candidate2))) {
18843
19052
  throw new Error(`Refusing portable Skills authoring below configured native discovery root: ${lexical}`);
18844
19053
  }
18845
19054
  }
@@ -18851,15 +19060,15 @@ function getPortableSkillsRoot(options = {}) {
18851
19060
  function resolvePortableSkillsRoot(options, migrate) {
18852
19061
  if (options.rootDir)
18853
19062
  return options.rootDir;
18854
- const appDir = options.homeDir ? join29(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
18855
- const cache = join29(appDir, SKILLS_CACHE_DIRNAME);
19063
+ const appDir = options.homeDir ? join30(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
19064
+ const cache = join30(appDir, SKILLS_CACHE_DIRNAME);
18856
19065
  if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
18857
19066
  return cache;
18858
- const installed = join29(appDir, INSTALLED_SKILLS_DIRNAME);
19067
+ const installed = join30(appDir, INSTALLED_SKILLS_DIRNAME);
18859
19068
  return installed;
18860
19069
  }
18861
19070
  function getPortableSkillPath(name, options = {}) {
18862
- return join29(getPortableSkillsRoot(options), normalizePortableSkillName(name));
19071
+ return join30(getPortableSkillsRoot(options), normalizePortableSkillName(name));
18863
19072
  }
18864
19073
  function findPortableSkill(name, options = {}) {
18865
19074
  let normalized;
@@ -18869,7 +19078,7 @@ function findPortableSkill(name, options = {}) {
18869
19078
  return null;
18870
19079
  }
18871
19080
  const path = getPortableSkillPath(normalized, options);
18872
- if (!existsSync13(path) || !statSync10(path).isDirectory())
19081
+ if (!existsSync14(path) || !statSync10(path).isDirectory())
18873
19082
  return null;
18874
19083
  try {
18875
19084
  return summarizePortableSkill(path, normalized);
@@ -18885,7 +19094,7 @@ function listPortableSkills(options = {}) {
18885
19094
  for (const entry of readdirSync11(root2).sort()) {
18886
19095
  if (entry.startsWith("."))
18887
19096
  continue;
18888
- const path = join29(root2, entry);
19097
+ const path = join30(root2, entry);
18889
19098
  if (!safeIsDirectory(path))
18890
19099
  continue;
18891
19100
  try {
@@ -18919,11 +19128,11 @@ function isOfficialSkillName(name) {
18919
19128
  function scaffoldPortableSkill(name, options = {}) {
18920
19129
  const skillName = normalizeNewPortableSkillName(name);
18921
19130
  const readOnlyRoot = resolvePortableSkillsRoot(options, false);
18922
- assertPortableAuthoringPath(join29(readOnlyRoot, skillName), options);
19131
+ assertPortableAuthoringPath(join30(readOnlyRoot, skillName), options);
18923
19132
  const root2 = getPortableSkillsRoot(options);
18924
- const skillPath = join29(root2, skillName);
19133
+ const skillPath = join30(root2, skillName);
18925
19134
  assertPortableAuthoringPath(skillPath, options);
18926
- if (existsSync13(skillPath)) {
19135
+ if (existsSync14(skillPath)) {
18927
19136
  if (!options.overwrite)
18928
19137
  throw new Error(`Skill '${skillName}' already exists at ${skillPath}`);
18929
19138
  rmSync4(skillPath, { recursive: true, force: true });
@@ -18941,7 +19150,7 @@ function scaffoldPortableSkill(name, options = {}) {
18941
19150
  }
18942
19151
  function portPortableSkillDirectory(sourceDir, options = {}) {
18943
19152
  const absoluteSource = normalize4(sourceDir);
18944
- if (!existsSync13(absoluteSource) || !statSync10(absoluteSource).isDirectory()) {
19153
+ if (!existsSync14(absoluteSource) || !statSync10(absoluteSource).isDirectory()) {
18945
19154
  throw new Error(`Import directory not found: ${sourceDir}`);
18946
19155
  }
18947
19156
  const continueOnError = options.continueOnError ?? true;
@@ -18955,7 +19164,7 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
18955
19164
  const skipped = [];
18956
19165
  const entries = readdirSync11(absoluteSource, { withFileTypes: true }).map((entry) => entry.name).filter((entryName) => !entryName.startsWith(".")).sort();
18957
19166
  for (const entryName of entries) {
18958
- const childPath = join29(absoluteSource, entryName);
19167
+ const childPath = join30(absoluteSource, entryName);
18959
19168
  if (!safeIsDirectory(childPath))
18960
19169
  continue;
18961
19170
  if (!isSkillCandidate(childPath)) {
@@ -18984,19 +19193,19 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
18984
19193
  };
18985
19194
  }
18986
19195
  function isSkillCandidate(dir) {
18987
- return existsSync13(join29(dir, "SKILL.md")) || existsSync13(join29(dir, "skill.json")) || existsSync13(join29(dir, "package.json"));
19196
+ return existsSync14(join30(dir, "SKILL.md")) || existsSync14(join30(dir, "skill.json")) || existsSync14(join30(dir, "package.json"));
18988
19197
  }
18989
19198
  function physicalImportPath(path) {
18990
- let ancestor = resolve17(path);
19199
+ let ancestor = resolve18(path);
18991
19200
  const suffix = [];
18992
- while (!existsSync13(ancestor)) {
19201
+ while (!existsSync14(ancestor)) {
18993
19202
  suffix.unshift(basename11(ancestor));
18994
19203
  ancestor = dirname19(ancestor);
18995
19204
  }
18996
- return join29(realpathSync9(ancestor), ...suffix);
19205
+ return join30(realpathSync10(ancestor), ...suffix);
18997
19206
  }
18998
19207
  function assertDisjointImportPaths(source, destination) {
18999
- const sourcePath = realpathSync9(source);
19208
+ const sourcePath = realpathSync10(source);
19000
19209
  const destinationPath = physicalImportPath(destination);
19001
19210
  const contains2 = (parent, child) => {
19002
19211
  const path = relative6(parent, child);
@@ -19008,7 +19217,7 @@ function assertDisjointImportPaths(source, destination) {
19008
19217
  }
19009
19218
  function portPortableSkill(sourcePath, options = {}) {
19010
19219
  const absoluteSource = normalize4(sourcePath);
19011
- if (!existsSync13(absoluteSource) || !statSync10(absoluteSource).isDirectory()) {
19220
+ if (!existsSync14(absoluteSource) || !statSync10(absoluteSource).isDirectory()) {
19012
19221
  throw new Error(`Skill source directory not found: ${sourcePath}`);
19013
19222
  }
19014
19223
  const inferred = readPortableSkillManifestForImport(absoluteSource);
@@ -19019,14 +19228,14 @@ function portPortableSkill(sourcePath, options = {}) {
19019
19228
  const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename11(absoluteSource)}')` : ""} matches a bundled official skill.`;
19020
19229
  throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
19021
19230
  }
19022
- const readOnlyDestination = join29(resolvePortableSkillsRoot(options, false), skillName);
19231
+ const readOnlyDestination = join30(resolvePortableSkillsRoot(options, false), skillName);
19023
19232
  assertPortableAuthoringPath(readOnlyDestination, options);
19024
19233
  assertDisjointImportPaths(absoluteSource, readOnlyDestination);
19025
19234
  const root2 = getPortableSkillsRoot(options);
19026
- const destination = join29(root2, skillName);
19235
+ const destination = join30(root2, skillName);
19027
19236
  assertPortableAuthoringPath(destination, options);
19028
19237
  assertDisjointImportPaths(absoluteSource, destination);
19029
- if (existsSync13(destination)) {
19238
+ if (existsSync14(destination)) {
19030
19239
  if (!options.overwrite)
19031
19240
  throw new Error(`Skill '${skillName}' already exists at ${destination}`);
19032
19241
  rmSync4(destination, { recursive: true, force: true });
@@ -19068,13 +19277,13 @@ function buildCorpusManifest(input, name) {
19068
19277
  function writeCorpusSkill(input, options = {}) {
19069
19278
  const name = normalizePortableSkillName(input.name);
19070
19279
  const readOnlyRoot = resolvePortableSkillsRoot(options, false);
19071
- assertPortableAuthoringPath(join29(readOnlyRoot, name), options);
19280
+ assertPortableAuthoringPath(join30(readOnlyRoot, name), options);
19072
19281
  const root2 = getPortableSkillsRoot(options);
19073
- const skillPath = join29(root2, name);
19282
+ const skillPath = join30(root2, name);
19074
19283
  assertPortableAuthoringPath(skillPath, options);
19075
- const created = !existsSync13(skillPath);
19284
+ const created = !existsSync14(skillPath);
19076
19285
  mkdirSync9(skillPath, { recursive: true });
19077
- writeFileSync8(join29(skillPath, "SKILL.md"), input.skillMd);
19286
+ writeFileSync8(join30(skillPath, "SKILL.md"), input.skillMd);
19078
19287
  const manifest = buildCorpusManifest(input, name);
19079
19288
  writeSkillJsonWithHash(skillPath, manifest);
19080
19289
  return { name, path: skillPath, manifest, created };
@@ -19082,22 +19291,22 @@ function writeCorpusSkill(input, options = {}) {
19082
19291
  function installCorpusSkillAtomically(input, options = {}) {
19083
19292
  const name = normalizePortableSkillName(input.name);
19084
19293
  const readOnlyRoot = resolvePortableSkillsRoot(options, false);
19085
- assertPortableAuthoringPath(join29(readOnlyRoot, name), options);
19294
+ assertPortableAuthoringPath(join30(readOnlyRoot, name), options);
19086
19295
  const root2 = getPortableSkillsRoot(options);
19087
- const target = join29(root2, name);
19296
+ const target = join30(root2, name);
19088
19297
  assertPortableAuthoringPath(target, options);
19089
- const created = !existsSync13(target);
19298
+ const created = !existsSync14(target);
19090
19299
  mkdirSync9(root2, { recursive: true });
19091
- const staging = mkdtempSync2(join29(root2, `.pull-${name}-`));
19300
+ const staging = mkdtempSync2(join30(root2, `.pull-${name}-`));
19092
19301
  let moved = false;
19093
19302
  let backup = null;
19094
19303
  try {
19095
- writeFileSync8(join29(staging, "SKILL.md"), input.skillMd);
19304
+ writeFileSync8(join30(staging, "SKILL.md"), input.skillMd);
19096
19305
  const manifest = buildCorpusManifest(input, name);
19097
19306
  writeSkillJsonWithHash(staging, manifest);
19098
- if (existsSync13(target)) {
19099
- backup = mkdtempSync2(join29(root2, `.pull-backup-${name}-`));
19100
- renameSync5(target, join29(backup, name));
19307
+ if (existsSync14(target)) {
19308
+ backup = mkdtempSync2(join30(root2, `.pull-backup-${name}-`));
19309
+ renameSync5(target, join30(backup, name));
19101
19310
  moved = true;
19102
19311
  }
19103
19312
  renameSync5(staging, target);
@@ -19106,9 +19315,9 @@ function installCorpusSkillAtomically(input, options = {}) {
19106
19315
  return { name, path: target, manifest, created };
19107
19316
  } catch (error) {
19108
19317
  rmSync4(staging, { recursive: true, force: true });
19109
- if (moved && backup && existsSync13(join29(backup, name))) {
19318
+ if (moved && backup && existsSync14(join30(backup, name))) {
19110
19319
  try {
19111
- renameSync5(join29(backup, name), target);
19320
+ renameSync5(join30(backup, name), target);
19112
19321
  } catch {}
19113
19322
  }
19114
19323
  throw error;
@@ -19120,10 +19329,10 @@ function validatePortableSkillDirectory(name, skillPath) {
19120
19329
  const issues = [...base.issues];
19121
19330
  const warnings = [...base.warnings];
19122
19331
  let manifest;
19123
- if (existsSync13(skillPath)) {
19124
- const skillJsonPath = join29(skillPath, "skill.json");
19125
- const skillMdPath = join29(skillPath, "SKILL.md");
19126
- if (!existsSync13(skillJsonPath) && !existsSync13(skillMdPath)) {
19332
+ if (existsSync14(skillPath)) {
19333
+ const skillJsonPath = join30(skillPath, "skill.json");
19334
+ const skillMdPath = join30(skillPath, "SKILL.md");
19335
+ if (!existsSync14(skillJsonPath) && !existsSync14(skillMdPath)) {
19127
19336
  add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
19128
19337
  }
19129
19338
  try {
@@ -19142,7 +19351,7 @@ function validatePortableSkillDirectory(name, skillPath) {
19142
19351
  add3(issues, "portable.version_missing", "Portable manifest missing version");
19143
19352
  }
19144
19353
  const contractIssues = validatePortableManifestContract(manifest, {
19145
- strict: existsSync13(join29(skillPath, "skill.json")),
19354
+ strict: existsSync14(join30(skillPath, "skill.json")),
19146
19355
  skillPath
19147
19356
  });
19148
19357
  for (const issue of contractIssues)
@@ -19182,8 +19391,8 @@ function validatePortableSkillDirectory(name, skillPath) {
19182
19391
  add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
19183
19392
  continue;
19184
19393
  }
19185
- const entryPath = join29(skillPath, command.entry);
19186
- if (!existsSync13(entryPath))
19394
+ const entryPath = join30(skillPath, command.entry);
19395
+ if (!existsSync14(entryPath))
19187
19396
  add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
19188
19397
  else if (statSync10(entryPath).isDirectory())
19189
19398
  add3(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
@@ -19193,7 +19402,7 @@ function validatePortableSkillDirectory(name, skillPath) {
19193
19402
  } catch (error) {
19194
19403
  add3(issues, "portable.manifest_invalid", error.message);
19195
19404
  }
19196
- if (manifest?.kind !== "instruction" && !existsSync13(join29(skillPath, "AGENTS.md"))) {
19405
+ if (manifest?.kind !== "instruction" && !existsSync14(join30(skillPath, "AGENTS.md"))) {
19197
19406
  add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
19198
19407
  }
19199
19408
  }
@@ -19229,13 +19438,13 @@ async function runPortableSkill(name, args, options = {}) {
19229
19438
  if (!isSafeRelativePath2(command.entry)) {
19230
19439
  return { exitCode: 1, error: `Portable skill '${name}' command entry is unsafe` };
19231
19440
  }
19232
- const entryPath = join29(skill.path, command.entry);
19233
- if (!existsSync13(entryPath)) {
19441
+ const entryPath = join30(skill.path, command.entry);
19442
+ if (!existsSync14(entryPath)) {
19234
19443
  return { exitCode: 1, error: `Entry point '${command.entry}' not found in portable skill '${name}'` };
19235
19444
  }
19236
- const pkgPath = join29(skill.path, "package.json");
19237
- const nodeModules = join29(skill.path, "node_modules");
19238
- if (existsSync13(pkgPath) && !existsSync13(nodeModules) && hasPackageDependencies(pkgPath)) {
19445
+ const pkgPath = join30(skill.path, "package.json");
19446
+ const nodeModules = join30(skill.path, "node_modules");
19447
+ if (existsSync14(pkgPath) && !existsSync14(nodeModules) && hasPackageDependencies(pkgPath)) {
19239
19448
  const install = Bun.spawn(["bun", "install", "--no-save"], {
19240
19449
  cwd: skill.path,
19241
19450
  stdout: "pipe",
@@ -19483,7 +19692,7 @@ function parseSkillMdFrontmatter(content) {
19483
19692
  return Object.keys(result).length > 0 ? result : null;
19484
19693
  }
19485
19694
  function discoverSkillsInDir(dir, source = "custom") {
19486
- if (!existsSync14(dir))
19695
+ if (!existsSync15(dir))
19487
19696
  return [];
19488
19697
  const result = [];
19489
19698
  try {
@@ -19491,8 +19700,8 @@ function discoverSkillsInDir(dir, source = "custom") {
19491
19700
  for (const entry of entries) {
19492
19701
  if (!entry.isDirectory())
19493
19702
  continue;
19494
- const skillMdPath = join30(dir, entry.name, "SKILL.md");
19495
- if (!existsSync14(skillMdPath))
19703
+ const skillMdPath = join31(dir, entry.name, "SKILL.md");
19704
+ if (!existsSync15(skillMdPath))
19496
19705
  continue;
19497
19706
  let content;
19498
19707
  try {
@@ -19511,7 +19720,7 @@ function discoverSkillsInDir(dir, source = "custom") {
19511
19720
  category: fm.category || "Development Tools",
19512
19721
  tags: fm.tags || [],
19513
19722
  ...fm.kind ? { kind: fm.kind } : {},
19514
- ...isHostedMetadataSkillDir(join30(dir, entry.name)) ? { serverOwned: true } : {},
19723
+ ...isHostedMetadataSkillDir(join31(dir, entry.name)) ? { serverOwned: true } : {},
19515
19724
  source
19516
19725
  });
19517
19726
  }
@@ -19520,16 +19729,16 @@ function discoverSkillsInDir(dir, source = "custom") {
19520
19729
  }
19521
19730
  function findExtensionSkillPath(name) {
19522
19731
  const config = loadConfig();
19523
- if (!config.extensionsDir || !existsSync14(config.extensionsDir))
19732
+ if (!config.extensionsDir || !existsSync15(config.extensionsDir))
19524
19733
  return null;
19525
19734
  try {
19526
19735
  const entries = readdirSync12(config.extensionsDir, { withFileTypes: true });
19527
19736
  for (const entry of entries) {
19528
19737
  if (!entry.isDirectory())
19529
19738
  continue;
19530
- const skillDir = join30(config.extensionsDir, entry.name);
19531
- const skillMdPath = join30(skillDir, "SKILL.md");
19532
- if (!existsSync14(skillMdPath))
19739
+ const skillDir = join31(config.extensionsDir, entry.name);
19740
+ const skillMdPath = join31(skillDir, "SKILL.md");
19741
+ if (!existsSync15(skillMdPath))
19533
19742
  continue;
19534
19743
  let content;
19535
19744
  try {
@@ -19576,21 +19785,21 @@ function clearRegistryCache() {
19576
19785
  registryCacheTime = 0;
19577
19786
  registryCacheKey = null;
19578
19787
  }
19579
- function getSkillsByCategory(category) {
19580
- return loadRegistry().filter((s) => s.category === category);
19788
+ function getSkillsByCategory(category, catalog) {
19789
+ return (catalog ?? loadRegistry()).filter((s) => s.category === category);
19581
19790
  }
19582
19791
  function getSkill(name) {
19583
19792
  const registry = loadRegistry();
19584
19793
  const slug = normalizeSkillSlug(name);
19585
19794
  return registry.find((s) => s.name === slug) ?? registry.find((s) => s.name === resolveSkillAlias(slug));
19586
19795
  }
19587
- function getSkillsByTag(tag) {
19796
+ function getSkillsByTag(tag, catalog) {
19588
19797
  const needle = tag.toLowerCase();
19589
- return loadRegistry().filter((s) => s.tags.some((t2) => t2.toLowerCase().includes(needle)));
19798
+ return (catalog ?? loadRegistry()).filter((s) => s.tags.some((t2) => t2.toLowerCase().includes(needle)));
19590
19799
  }
19591
- function getAllTags() {
19800
+ function getAllTags(catalog) {
19592
19801
  const tagSet = new Set;
19593
- for (const skill of loadRegistry()) {
19802
+ for (const skill of catalog ?? loadRegistry()) {
19594
19803
  for (const tag of skill.tags)
19595
19804
  tagSet.add(tag.toLowerCase());
19596
19805
  }
@@ -19598,20 +19807,20 @@ function getAllTags() {
19598
19807
  }
19599
19808
  // src/lib/run-state.ts
19600
19809
  import { createHash as createHash19, randomBytes } from "crypto";
19601
- import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync19, readdirSync as readdirSync13, statSync as statSync11, writeFileSync as writeFileSync9 } from "fs";
19602
- import { extname, join as join31, relative as relative7 } from "path";
19810
+ import { existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync19, readdirSync as readdirSync13, statSync as statSync11, writeFileSync as writeFileSync9 } from "fs";
19811
+ import { extname, join as join32, relative as relative7 } from "path";
19603
19812
  function createSkillRun(params, targetDir = process.cwd()) {
19604
19813
  const now = new Date;
19605
19814
  const id = createRunId(now);
19606
19815
  const day = now.toISOString().slice(0, 10);
19607
19816
  const skillName = normalizeSkillName(params.skill);
19608
19817
  const root2 = getProjectStateDir(targetDir);
19609
- const runDir = join31(root2, "runs", day, id);
19610
- const logsDir = join31(runDir, "logs");
19611
- const exportDir = join31(root2, "exports", skillName, id);
19818
+ const runDir = join32(root2, "runs", day, id);
19819
+ const logsDir = join32(runDir, "logs");
19820
+ const exportDir = join32(root2, "exports", skillName, id);
19612
19821
  mkdirSync10(logsDir, { recursive: true });
19613
19822
  mkdirSync10(exportDir, { recursive: true });
19614
- mkdirSync10(join31(root2, "tmp"), { recursive: true });
19823
+ mkdirSync10(join32(root2, "tmp"), { recursive: true });
19615
19824
  const record3 = {
19616
19825
  id,
19617
19826
  skill: skillName,
@@ -19663,27 +19872,27 @@ function updateSkillRun(context, patch) {
19663
19872
  return context.record;
19664
19873
  }
19665
19874
  function writeRunLogs(context, stdout = "", stderr = "") {
19666
- writeFileSync9(join31(context.logsDir, "stdout.log"), stdout);
19667
- writeFileSync9(join31(context.logsDir, "stderr.log"), stderr);
19875
+ writeFileSync9(join32(context.logsDir, "stdout.log"), stdout);
19876
+ writeFileSync9(join32(context.logsDir, "stderr.log"), stderr);
19668
19877
  }
19669
19878
  function appendRunEvent(context, event, data = {}) {
19670
19879
  const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
19671
19880
  `;
19672
- const path = join31(context.runDir, "events.ndjson");
19673
- const previous = existsSync15(path) ? readFileSync19(path, "utf-8") : "";
19881
+ const path = join32(context.runDir, "events.ndjson");
19882
+ const previous = existsSync16(path) ? readFileSync19(path, "utf-8") : "";
19674
19883
  writeFileSync9(path, previous + line);
19675
19884
  }
19676
19885
  function listSkillRuns(targetDir = process.cwd(), limit = 50) {
19677
- const runsRoot = join31(getProjectStateDir(targetDir), "runs");
19678
- if (!existsSync15(runsRoot))
19886
+ const runsRoot = join32(getProjectStateDir(targetDir), "runs");
19887
+ if (!existsSync16(runsRoot))
19679
19888
  return [];
19680
19889
  const records = [];
19681
19890
  for (const day of readdirSync13(runsRoot).sort().reverse()) {
19682
- const dayDir = join31(runsRoot, day);
19891
+ const dayDir = join32(runsRoot, day);
19683
19892
  if (!statSync11(dayDir).isDirectory())
19684
19893
  continue;
19685
19894
  for (const runId of readdirSync13(dayDir).sort().reverse()) {
19686
- const record3 = readRunRecord(join31(dayDir, runId));
19895
+ const record3 = readRunRecord(join32(dayDir, runId));
19687
19896
  if (record3)
19688
19897
  records.push(record3);
19689
19898
  if (records.length >= limit)
@@ -19693,29 +19902,29 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
19693
19902
  return records;
19694
19903
  }
19695
19904
  function findSkillRun(runId, targetDir = process.cwd()) {
19696
- const runsRoot = join31(getProjectStateDir(targetDir), "runs");
19697
- if (!existsSync15(runsRoot))
19905
+ const runsRoot = join32(getProjectStateDir(targetDir), "runs");
19906
+ if (!existsSync16(runsRoot))
19698
19907
  return null;
19699
19908
  for (const day of readdirSync13(runsRoot)) {
19700
- const record3 = readRunRecord(join31(runsRoot, day, runId));
19909
+ const record3 = readRunRecord(join32(runsRoot, day, runId));
19701
19910
  if (record3)
19702
19911
  return record3;
19703
19912
  }
19704
19913
  return null;
19705
19914
  }
19706
19915
  function getRunExportDir(runId, skill, targetDir = process.cwd()) {
19707
- return join31(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
19916
+ return join32(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
19708
19917
  }
19709
19918
  function writeRunRecord(context) {
19710
- writeFileSync9(join31(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
19919
+ writeFileSync9(join32(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
19711
19920
  `);
19712
19921
  }
19713
19922
  function writeArtifactsManifest(context, artifacts) {
19714
- writeFileSync9(join31(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
19923
+ writeFileSync9(join32(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
19715
19924
  `);
19716
19925
  }
19717
19926
  function collectRunArtifacts(context) {
19718
- if (!existsSync15(context.exportDir))
19927
+ if (!existsSync16(context.exportDir))
19719
19928
  return [];
19720
19929
  const artifacts = [];
19721
19930
  for (const path of walkFiles(context.exportDir)) {
@@ -19731,8 +19940,8 @@ function collectRunArtifacts(context) {
19731
19940
  return artifacts.sort((a, b) => a.path.localeCompare(b.path));
19732
19941
  }
19733
19942
  function readRunRecord(runDir) {
19734
- const path = join31(runDir, "run.json");
19735
- if (!existsSync15(path))
19943
+ const path = join32(runDir, "run.json");
19944
+ if (!existsSync16(path))
19736
19945
  return null;
19737
19946
  try {
19738
19947
  return JSON.parse(readFileSync19(path, "utf-8"));
@@ -19743,7 +19952,7 @@ function readRunRecord(runDir) {
19743
19952
  function walkFiles(dir) {
19744
19953
  const files = [];
19745
19954
  for (const entry of readdirSync13(dir)) {
19746
- const full = join31(dir, entry);
19955
+ const full = join32(dir, entry);
19747
19956
  if (statSync11(full).isDirectory())
19748
19957
  files.push(...walkFiles(full));
19749
19958
  else
@@ -40148,10 +40357,10 @@ async function readQuoteUnavailableCode(response) {
40148
40357
  let timer;
40149
40358
  let deadlineExceeded = false;
40150
40359
  const expired = Symbol("quote body deadline");
40151
- const deadline = new Promise((resolve18) => {
40360
+ const deadline = new Promise((resolve19) => {
40152
40361
  timer = setTimeout(() => {
40153
40362
  deadlineExceeded = true;
40154
- resolve18(expired);
40363
+ resolve19(expired);
40155
40364
  reader.cancel().catch(() => {});
40156
40365
  }, 1500);
40157
40366
  });
@@ -41250,14 +41459,14 @@ async function createRemoteSkillsClient(env = process.env) {
41250
41459
  return connection ? new RemoteSkillsClient(connection.apiKey, connection.apiOrigin) : null;
41251
41460
  }
41252
41461
  // src/lib/scheduler.ts
41253
- import { existsSync as existsSync16, readFileSync as readFileSync20, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11 } from "fs";
41254
- import { join as join32 } from "path";
41462
+ import { existsSync as existsSync17, readFileSync as readFileSync20, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11 } from "fs";
41463
+ import { join as join33 } from "path";
41255
41464
  function getSchedulesPath(targetDir = process.cwd()) {
41256
- return join32(targetDir, ".skills", "schedules.json");
41465
+ return join33(targetDir, ".skills", "schedules.json");
41257
41466
  }
41258
41467
  function loadSchedules(targetDir = process.cwd()) {
41259
41468
  const path = getSchedulesPath(targetDir);
41260
- if (existsSync16(path)) {
41469
+ if (existsSync17(path)) {
41261
41470
  try {
41262
41471
  return JSON.parse(readFileSync20(path, "utf-8"));
41263
41472
  } catch {}
@@ -41266,8 +41475,8 @@ function loadSchedules(targetDir = process.cwd()) {
41266
41475
  }
41267
41476
  function saveSchedules(data, targetDir = process.cwd()) {
41268
41477
  const path = getSchedulesPath(targetDir);
41269
- const dir = join32(targetDir, ".skills");
41270
- if (!existsSync16(dir))
41478
+ const dir = join33(targetDir, ".skills");
41479
+ if (!existsSync17(dir))
41271
41480
  mkdirSync11(dir, { recursive: true });
41272
41481
  writeFileSync10(path, JSON.stringify(data, null, 2));
41273
41482
  }
@@ -41482,8 +41691,8 @@ function revisionIdOfRecord(record8) {
41482
41691
  return revisionIdOf(record8);
41483
41692
  }
41484
41693
  // src/lib/pull.ts
41485
- import { existsSync as existsSync17, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync21, renameSync as renameSync6, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "fs";
41486
- import { dirname as dirname20, join as join33 } from "path";
41694
+ import { existsSync as existsSync18, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync21, renameSync as renameSync6, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "fs";
41695
+ import { dirname as dirname20, join as join34 } from "path";
41487
41696
 
41488
41697
  // src/lib/skill-bundles.ts
41489
41698
  import { createHmac, timingSafeEqual } from "crypto";
@@ -41577,7 +41786,7 @@ async function pullOne(client2, rawName, corpusOptions, verify) {
41577
41786
  return reconcileTombstone(slug2, corpusOptions);
41578
41787
  }
41579
41788
  if (bundleResponse.status === 404) {
41580
- const marker = readPullMarker(join33(getPortableSkillsRoot(corpusOptions), slug2));
41789
+ const marker = readPullMarker(join34(getPortableSkillsRoot(corpusOptions), slug2));
41581
41790
  if (isPublishedInstallMarker(marker)) {
41582
41791
  return { name: slug2, success: true, purged: true, removed: false };
41583
41792
  }
@@ -41616,7 +41825,7 @@ async function pullOne(client2, rawName, corpusOptions, verify) {
41616
41825
  return { name: slug2, success: false, error: `Skill '${slug2}' was not found on the configured Skills instance.` };
41617
41826
  }
41618
41827
  if (!meta3?.revisionId) {
41619
- const marker = readPullMarker(join33(getPortableSkillsRoot(corpusOptions), slug2));
41828
+ const marker = readPullMarker(join34(getPortableSkillsRoot(corpusOptions), slug2));
41620
41829
  if (isPublishedInstallMarker(marker)) {
41621
41830
  return { name: slug2, success: true, purged: true, removed: false };
41622
41831
  }
@@ -41673,7 +41882,7 @@ function provenRevision(meta3, slug2, bundle2) {
41673
41882
  return declared;
41674
41883
  }
41675
41884
  function reconcileTombstone(slug2, corpusOptions) {
41676
- const target = join33(getPortableSkillsRoot(corpusOptions), slug2);
41885
+ const target = join34(getPortableSkillsRoot(corpusOptions), slug2);
41677
41886
  if (!hasSkillsOwnershipMarker(target)) {
41678
41887
  return { name: slug2, success: true, tombstoned: true, removed: false, leftInPlace: true };
41679
41888
  }
@@ -41682,7 +41891,7 @@ function reconcileTombstone(slug2, corpusOptions) {
41682
41891
  }
41683
41892
  function readPullMarker(dir) {
41684
41893
  try {
41685
- return JSON.parse(readFileSync21(join33(dir, PULL_MARKER_FILE), "utf-8"));
41894
+ return JSON.parse(readFileSync21(join34(dir, PULL_MARKER_FILE), "utf-8"));
41686
41895
  } catch {
41687
41896
  return null;
41688
41897
  }
@@ -41817,14 +42026,14 @@ function verifyBundleResponseBytes(buffer, response, verify = {}) {
41817
42026
  function installBundleAtomically(name, entries, options = {}, marker = {}) {
41818
42027
  const root2 = getPortableSkillsRoot(options);
41819
42028
  mkdirSync12(root2, { recursive: true });
41820
- const target = join33(root2, name);
41821
- const created = !existsSync17(target);
41822
- const staging = mkdtempSync3(join33(root2, `.pull-${name}-`));
42029
+ const target = join34(root2, name);
42030
+ const created = !existsSync18(target);
42031
+ const staging = mkdtempSync3(join34(root2, `.pull-${name}-`));
41823
42032
  let moved = false;
41824
42033
  let backup = null;
41825
42034
  try {
41826
42035
  for (const entry of entries) {
41827
- const destination = join33(staging, entry.path);
42036
+ const destination = join34(staging, entry.path);
41828
42037
  mkdirSync12(dirname20(destination), { recursive: true });
41829
42038
  writeFileSync11(destination, entry.bytes, { mode: entry.mode });
41830
42039
  }
@@ -41836,9 +42045,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
41836
42045
  ...marker.signature ? { signature: marker.signature } : {},
41837
42046
  ...marker.revisionId ? { revisionId: marker.revisionId } : {}
41838
42047
  });
41839
- if (existsSync17(target)) {
41840
- backup = mkdtempSync3(join33(root2, `.pull-backup-${name}-`));
41841
- renameSync6(target, join33(backup, name));
42048
+ if (existsSync18(target)) {
42049
+ backup = mkdtempSync3(join34(root2, `.pull-backup-${name}-`));
42050
+ renameSync6(target, join34(backup, name));
41842
42051
  moved = true;
41843
42052
  }
41844
42053
  renameSync6(staging, target);
@@ -41846,9 +42055,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
41846
42055
  rmSync5(backup, { recursive: true, force: true });
41847
42056
  } catch (error61) {
41848
42057
  rmSync5(staging, { recursive: true, force: true });
41849
- if (moved && backup && existsSync17(join33(backup, name))) {
42058
+ if (moved && backup && existsSync18(join34(backup, name))) {
41850
42059
  try {
41851
- renameSync6(join33(backup, name), target);
42060
+ renameSync6(join34(backup, name), target);
41852
42061
  } catch {}
41853
42062
  }
41854
42063
  throw error61;
@@ -41867,7 +42076,7 @@ function writePullMarker(dir, record8) {
41867
42076
  ...record8.revisionId ? { revisionId: record8.revisionId } : {},
41868
42077
  syncedAt: new Date().toISOString()
41869
42078
  };
41870
- writeFileSync11(join33(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
42079
+ writeFileSync11(join34(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
41871
42080
  `);
41872
42081
  }
41873
42082
  async function safeMeta(client2, slug2) {
@@ -42309,12 +42518,12 @@ class RemotePrivatePublicationsClient {
42309
42518
  previous = view;
42310
42519
  if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
42311
42520
  return view;
42312
- await new Promise((resolve18) => {
42521
+ await new Promise((resolve19) => {
42313
42522
  const timer = setTimeout(done, Math.min(1000, until - Date.now()));
42314
42523
  function done() {
42315
42524
  clearTimeout(timer);
42316
42525
  options.signal?.removeEventListener("abort", done);
42317
- resolve18();
42526
+ resolve19();
42318
42527
  }
42319
42528
  options.signal?.addEventListener("abort", done, { once: true });
42320
42529
  });
@@ -43870,16 +44079,16 @@ function clone3(value) {
43870
44079
  return JSON.parse(JSON.stringify(value));
43871
44080
  }
43872
44081
  // src/lib/feedback.ts
43873
- import { appendFileSync, existsSync as existsSync18, mkdirSync as mkdirSync14 } from "fs";
43874
- import { dirname as dirname22, join as join34 } from "path";
44082
+ import { appendFileSync, existsSync as existsSync19, mkdirSync as mkdirSync14 } from "fs";
44083
+ import { dirname as dirname22, join as join35 } from "path";
43875
44084
  import { Database } from "bun:sqlite";
43876
44085
  function getFeedbackDbPath() {
43877
- return join34(getDataDir(), "skills.db");
44086
+ return join35(getDataDir(), "skills.db");
43878
44087
  }
43879
44088
  function getFeedbackDb() {
43880
44089
  const dbPath = getFeedbackDbPath();
43881
44090
  const dir = dirname22(dbPath);
43882
- if (!existsSync18(dir))
44091
+ if (!existsSync19(dir))
43883
44092
  mkdirSync14(dir, { recursive: true });
43884
44093
  const db = new Database(dbPath);
43885
44094
  db.exec("PRAGMA journal_mode = WAL");
@@ -43906,9 +44115,9 @@ function saveFeedback(input2) {
43906
44115
  throw new Error("Feedback message is required");
43907
44116
  const category = input2.category ?? "general";
43908
44117
  if (isApiMode()) {
43909
- const path = join34(getDataDir(), "feedback.jsonl");
44118
+ const path = join35(getDataDir(), "feedback.jsonl");
43910
44119
  const dir = dirname22(path);
43911
- if (!existsSync18(dir))
44120
+ if (!existsSync19(dir))
43912
44121
  mkdirSync14(dir, { recursive: true });
43913
44122
  appendFileSync(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
43914
44123
  `);
@@ -43932,14 +44141,14 @@ function isApiMode(env = process.env) {
43932
44141
  // src/lib/native-storage.ts
43933
44142
  import { createHash as createHash23, createHmac as createHmac2 } from "crypto";
43934
44143
  import {
43935
- existsSync as existsSync19,
44144
+ existsSync as existsSync20,
43936
44145
  mkdirSync as mkdirSync15,
43937
44146
  readFileSync as readFileSync23,
43938
44147
  readdirSync as readdirSync14,
43939
44148
  statSync as statSync12,
43940
44149
  writeFileSync as writeFileSync13
43941
44150
  } from "fs";
43942
- import { dirname as dirname23, join as join35, normalize as normalize5, relative as relative9, sep as sep9 } from "path";
44151
+ import { dirname as dirname23, join as join36, normalize as normalize5, relative as relative9, sep as sep9 } from "path";
43943
44152
  var SKILLS_STORAGE_TABLES = [
43944
44153
  "skills_sync_records",
43945
44154
  "skills_sync_cursors"
@@ -44076,7 +44285,7 @@ function getSkillsNativeStorageStatus(options = {}) {
44076
44285
  local: {
44077
44286
  dataDir: getDataDir(),
44078
44287
  projectStateDir: getProjectStateDir(targetDir),
44079
- feedbackDbPath: join35(getDataDir(), "skills.db")
44288
+ feedbackDbPath: join36(getDataDir(), "skills.db")
44080
44289
  },
44081
44290
  remote: {
44082
44291
  databaseConfigured: Boolean(config2.databaseUrl),
@@ -44099,7 +44308,7 @@ function getStorageStatus(options = {}) {
44099
44308
  function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
44100
44309
  const projectStateDir = getProjectStateDir(targetDir);
44101
44310
  const files = [];
44102
- if (existsSync19(projectStateDir)) {
44311
+ if (existsSync20(projectStateDir)) {
44103
44312
  for (const filePath of walkFiles2(projectStateDir)) {
44104
44313
  const bytes = readFileSync23(filePath);
44105
44314
  const relativePath = toPosix(relative9(targetDir, filePath));
@@ -44126,7 +44335,7 @@ function importSkillsLocalSnapshot(snapshot2, targetDir = process.cwd(), options
44126
44335
  continue;
44127
44336
  }
44128
44337
  const absolutePath4 = resolveSnapshotPath(targetDir, file2.path);
44129
- if (existsSync19(absolutePath4) && !options.overwrite) {
44338
+ if (existsSync20(absolutePath4) && !options.overwrite) {
44130
44339
  skipped += 1;
44131
44340
  continue;
44132
44341
  }
@@ -44433,7 +44642,7 @@ function parsePositiveInteger(value) {
44433
44642
  function walkFiles2(dir) {
44434
44643
  const files = [];
44435
44644
  for (const entry of readdirSync14(dir)) {
44436
- const full = join35(dir, entry);
44645
+ const full = join36(dir, entry);
44437
44646
  const stats = statSync12(full);
44438
44647
  if (stats.isDirectory())
44439
44648
  files.push(...walkFiles2(full));
@@ -44450,7 +44659,7 @@ function resolveSnapshotPath(targetDir, snapshotPath) {
44450
44659
  if (!toPosix(normalizedPath).startsWith(".skills/")) {
44451
44660
  throw new Error(`Snapshot path must stay inside .skills: ${snapshotPath}`);
44452
44661
  }
44453
- return join35(targetDir, normalizedPath);
44662
+ return join36(targetDir, normalizedPath);
44454
44663
  }
44455
44664
  function normalizeS3Prefix(prefix) {
44456
44665
  return (prefix ?? "").trim().replace(/^\/+|\/+$/g, "");
@@ -44523,12 +44732,12 @@ import {
44523
44732
  statSync as statSync14,
44524
44733
  writeFileSync as writeFileSync14
44525
44734
  } from "fs";
44526
- import { dirname as dirname24, isAbsolute as isAbsolute19, relative as relative10, resolve as resolve18, sep as sep11 } from "path";
44735
+ import { dirname as dirname24, isAbsolute as isAbsolute19, relative as relative10, resolve as resolve19, sep as sep11 } from "path";
44527
44736
 
44528
44737
  // src/lib/portable-snapshot-filter.ts
44529
44738
  import { readdirSync as readdirSync15, statSync as statSync13 } from "fs";
44530
44739
  import { homedir as homedir7 } from "os";
44531
- import { join as join36, sep as sep10 } from "path";
44740
+ import { join as join37, sep as sep10 } from "path";
44532
44741
  var SYNC_HOMES = [
44533
44742
  { name: "skills", subClass: "skills", agent: null },
44534
44743
  { name: "custom", subClass: "custom", agent: null },
@@ -44621,16 +44830,16 @@ function isPortableWithinSkill(relativeParts) {
44621
44830
  function homePathFor(definition, homesRoot) {
44622
44831
  const home = homesRoot ?? homedir7();
44623
44832
  if (definition.subClass === "skills" || definition.subClass === "custom") {
44624
- return join36(skillsDataRootForHome(home), definition.name);
44833
+ return join37(skillsDataRootForHome(home), definition.name);
44625
44834
  }
44626
44835
  if (definition.agent === "opencode") {
44627
- return join36(home, ".config", "opencode", "skills");
44836
+ return join37(home, ".config", "opencode", "skills");
44628
44837
  }
44629
- return join36(home, `.${definition.agent}`, "skills");
44838
+ return join37(home, `.${definition.agent}`, "skills");
44630
44839
  }
44631
44840
  function destinationFor(definition, stationId, relativePath) {
44632
- const category = definition.subClass === "agent-homes" ? join36("agent-homes", definition.agent ?? "") : definition.name;
44633
- return join36("resources", stationId, "skills", category, ...relativePath.split(sep10));
44841
+ const category = definition.subClass === "agent-homes" ? join37("agent-homes", definition.agent ?? "") : definition.name;
44842
+ return join37("resources", stationId, "skills", category, ...relativePath.split(sep10));
44634
44843
  }
44635
44844
  function walkEntries(absoluteRoot) {
44636
44845
  let entries;
@@ -44641,7 +44850,7 @@ function walkEntries(absoluteRoot) {
44641
44850
  }
44642
44851
  const output2 = [];
44643
44852
  for (const entry of entries) {
44644
- const childFull = join36(absoluteRoot, entry.name);
44853
+ const childFull = join37(absoluteRoot, entry.name);
44645
44854
  if (entry.isSymbolicLink()) {
44646
44855
  output2.push({ kind: "symlink", relativePath: entry.name, fullPath: childFull });
44647
44856
  continue;
@@ -44652,7 +44861,7 @@ function walkEntries(absoluteRoot) {
44652
44861
  }
44653
44862
  const nested = walkEntries(childFull);
44654
44863
  for (const item of nested) {
44655
- output2.push({ ...item, relativePath: join36(entry.name, item.relativePath) });
44864
+ output2.push({ ...item, relativePath: join37(entry.name, item.relativePath) });
44656
44865
  }
44657
44866
  continue;
44658
44867
  }
@@ -44761,7 +44970,7 @@ function humanHomes(scanned) {
44761
44970
  }));
44762
44971
  }
44763
44972
  function writeStationSnapshot(options) {
44764
- const repoRoot = resolve18(options.repoRoot ?? process.cwd());
44973
+ const repoRoot = resolve19(options.repoRoot ?? process.cwd());
44765
44974
  const { scanned, plans, totalBytes } = planStationSnapshot(options);
44766
44975
  const manifestFiles = plans.map((plan) => ({
44767
44976
  relativePath: plan.source.relativePath,
@@ -44787,7 +44996,7 @@ function writeStationSnapshot(options) {
44787
44996
  const conflicts = [];
44788
44997
  const untouched = [];
44789
44998
  for (const plan of plans) {
44790
- const destination = resolve18(repoRoot, plan.destination);
44999
+ const destination = resolve19(repoRoot, plan.destination);
44791
45000
  const destinationRelative = relative10(repoRoot, destination);
44792
45001
  if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep11) || isAbsolute19(destinationRelative)) {
44793
45002
  throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
@@ -44810,7 +45019,7 @@ function writeStationSnapshot(options) {
44810
45019
  }
44811
45020
  let written = 0;
44812
45021
  for (const plan of untouched) {
44813
- const destination = resolve18(repoRoot, plan.destination);
45022
+ const destination = resolve19(repoRoot, plan.destination);
44814
45023
  mkdirSync16(dirname24(destination), { recursive: true });
44815
45024
  copyFileSync(plan.source.fullPath, destination);
44816
45025
  written += 1;
@@ -44829,7 +45038,7 @@ function writeStationSnapshot(options) {
44829
45038
  },
44830
45039
  files: manifestFiles
44831
45040
  };
44832
- const manifestPath = resolve18(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
45041
+ const manifestPath = resolve19(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
44833
45042
  mkdirSync16(dirname24(manifestPath), { recursive: true });
44834
45043
  writeFileSync14(manifestPath, `${JSON.stringify(manifest, null, 2)}
44835
45044
  `);
@@ -44850,7 +45059,7 @@ import {
44850
45059
  statSync as statSync15,
44851
45060
  writeFileSync as writeFileSync15
44852
45061
  } from "fs";
44853
- import { dirname as dirname25, join as join37, resolve as resolve19, sep as sep12 } from "path";
45062
+ import { dirname as dirname25, join as join38, resolve as resolve20, sep as sep12 } from "path";
44854
45063
  var STATION_HYDRATION_MANIFEST_SCHEMA = "hasna.fleet-resources.skills-hydration-manifest/v1";
44855
45064
  var STATION_HYDRATION_PRODUCER = { name: "@hasna/skills", version: package_default.version };
44856
45065
  var MANIFEST_HASH_KEY_SEP = String.fromCharCode(0);
@@ -44858,11 +45067,11 @@ function fail(code2, message, detail = []) {
44858
45067
  throw new StationSnapshotError(code2, message, detail);
44859
45068
  }
44860
45069
  function snapshotRootFor(repoRoot, stationId) {
44861
- return join37(repoRoot, "resources", stationId, "skills");
45070
+ return join38(repoRoot, "resources", stationId, "skills");
44862
45071
  }
44863
45072
  function readSnapshotManifest(repoRoot, stationId) {
44864
45073
  const snapshotRoot = snapshotRootFor(repoRoot, stationId);
44865
- const manifestPath = join37(snapshotRoot, "sync-manifest.json");
45074
+ const manifestPath = join38(snapshotRoot, "sync-manifest.json");
44866
45075
  let manifest;
44867
45076
  try {
44868
45077
  manifest = JSON.parse(readFileSync26(manifestPath, "utf8"));
@@ -44889,7 +45098,7 @@ function planStationHydration(stationId, repoRoot) {
44889
45098
  const hashMismatches = [];
44890
45099
  const skippedByRule = [];
44891
45100
  for (const agent of SYNC_AGENTS) {
44892
- const agentRoot = join37(snapshotRoot, "agent-homes", agent);
45101
+ const agentRoot = join38(snapshotRoot, "agent-homes", agent);
44893
45102
  let identEntries;
44894
45103
  try {
44895
45104
  identEntries = readdirSync16(agentRoot, { withFileTypes: true });
@@ -44900,7 +45109,7 @@ function planStationHydration(stationId, repoRoot) {
44900
45109
  if (!identEntry.isDirectory() || identEntry.name.startsWith(".")) {
44901
45110
  continue;
44902
45111
  }
44903
- const identRoot = join37(agentRoot, identEntry.name);
45112
+ const identRoot = join38(agentRoot, identEntry.name);
44904
45113
  const entries = walkEntries(identRoot);
44905
45114
  for (const entry of entries) {
44906
45115
  const relativeParts = [identEntry.name, ...entry.relativePath.split(sep12)];
@@ -45051,8 +45260,8 @@ function skillSha256(skill) {
45051
45260
  `)).digest("hex");
45052
45261
  }
45053
45262
  function writeStationHydration(options) {
45054
- const repoRoot = resolve19(options.repoRoot ?? process.cwd());
45055
- const cacheRoot = resolve19(options.cacheRoot ?? resolveCorpusRoot());
45263
+ const repoRoot = resolve20(options.repoRoot ?? process.cwd());
45264
+ const cacheRoot = resolve20(options.cacheRoot ?? resolveCorpusRoot());
45056
45265
  const plan = planStationHydration(options.stationId, repoRoot);
45057
45266
  const resultSkills = plan.winners.map((skill) => ({
45058
45267
  ident: skill.ident,
@@ -45085,7 +45294,7 @@ function writeStationHydration(options) {
45085
45294
  const toWrite = [];
45086
45295
  for (const skill of plan.winners) {
45087
45296
  for (const file2 of skill.files) {
45088
- const destination = join37(cacheRoot, skill.ident, file2.withinIdent);
45297
+ const destination = join38(cacheRoot, skill.ident, file2.withinIdent);
45089
45298
  const digest3 = sha256File(file2.winner.fullPath);
45090
45299
  let existingDigest = null;
45091
45300
  try {
@@ -45127,7 +45336,7 @@ function writeStationHydration(options) {
45127
45336
  },
45128
45337
  skills: resultSkills
45129
45338
  };
45130
- const hydrationManifestPath = join37(dirname25(cacheRoot), `hydration-${options.stationId}.json`);
45339
+ const hydrationManifestPath = join38(dirname25(cacheRoot), `hydration-${options.stationId}.json`);
45131
45340
  mkdirSync17(dirname25(hydrationManifestPath), { recursive: true });
45132
45341
  writeFileSync15(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
45133
45342
  `);
@@ -45139,23 +45348,23 @@ function writeStationHydration(options) {
45139
45348
  };
45140
45349
  }
45141
45350
  // src/lib/private-publication-recovery.ts
45142
- import { constants as constants12, closeSync as closeSync13, fsyncSync as fsyncSync5, fstatSync as fstatSync13, lstatSync as lstatSync23, mkdirSync as mkdirSync18, openSync as openSync13, readSync as readSync11, realpathSync as realpathSync10, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync16 } from "fs";
45143
- import { dirname as dirname26, isAbsolute as isAbsolute20, join as join38, resolve as resolve20 } from "path";
45351
+ import { constants as constants12, closeSync as closeSync13, fsyncSync as fsyncSync5, fstatSync as fstatSync13, lstatSync as lstatSync24, mkdirSync as mkdirSync18, openSync as openSync13, readSync as readSync11, realpathSync as realpathSync11, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync16 } from "fs";
45352
+ import { dirname as dirname26, isAbsolute as isAbsolute20, join as join39, resolve as resolve21 } from "path";
45144
45353
  import { randomUUID as randomUUID4 } from "crypto";
45145
45354
  var fail2 = () => {
45146
45355
  throw new PrivatePublicationError("PUBLICATION_RECOVERY_INVALID", "The recovery directory is invalid or changed. Preserve it and inspect the existing intent; do not start a replacement automatically.");
45147
45356
  };
45148
45357
  function safeDirectory(directory2) {
45149
- if (!isAbsolute20(directory2) || directory2 !== resolve20(directory2) || realpathSync10(directory2) !== directory2)
45358
+ if (!isAbsolute20(directory2) || directory2 !== resolve21(directory2) || realpathSync11(directory2) !== directory2)
45150
45359
  return fail2();
45151
45360
  for (let path = directory2;; path = dirname26(path)) {
45152
- const stat2 = lstatSync23(path);
45361
+ const stat2 = lstatSync24(path);
45153
45362
  if (!stat2.isDirectory() || stat2.isSymbolicLink())
45154
45363
  return fail2();
45155
45364
  if (path === dirname26(path))
45156
45365
  break;
45157
45366
  }
45158
- const own2 = lstatSync23(directory2);
45367
+ const own2 = lstatSync24(directory2);
45159
45368
  if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
45160
45369
  return fail2();
45161
45370
  return { dev: own2.dev, ino: own2.ino };
@@ -45166,7 +45375,7 @@ function unchangedDirectory(directory2, identity4) {
45166
45375
  return fail2();
45167
45376
  }
45168
45377
  function readOwned(directory2, name, max) {
45169
- const identity4 = safeDirectory(directory2), file2 = join38(directory2, name);
45378
+ const identity4 = safeDirectory(directory2), file2 = join39(directory2, name);
45170
45379
  const fd = openSync13(file2, constants12.O_RDONLY | constants12.O_NOFOLLOW);
45171
45380
  try {
45172
45381
  const stat2 = fstatSync13(fd);
@@ -45190,7 +45399,7 @@ function readOwned(directory2, name, max) {
45190
45399
  }
45191
45400
  }
45192
45401
  function writeOwned(directory2, name, bytes) {
45193
- const fd = openSync13(join38(directory2, name), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
45402
+ const fd = openSync13(join39(directory2, name), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
45194
45403
  try {
45195
45404
  writeFileSync16(fd, bytes);
45196
45405
  fsyncSync5(fd);
@@ -45203,7 +45412,7 @@ function save(directory2, value) {
45203
45412
  writeOwned(directory2, temporary, JSON.stringify(value) + `
45204
45413
  `);
45205
45414
  unchangedDirectory(directory2, identity4);
45206
- renameSync7(join38(directory2, temporary), join38(directory2, "receipt.json"));
45415
+ renameSync7(join39(directory2, temporary), join39(directory2, "receipt.json"));
45207
45416
  const fd = openSync13(directory2, constants12.O_RDONLY | constants12.O_NOFOLLOW);
45208
45417
  try {
45209
45418
  fsyncSync5(fd);
@@ -45216,7 +45425,7 @@ function bind(client2, receipt) {
45216
45425
  throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
45217
45426
  }
45218
45427
  async function locked(directory2, action) {
45219
- const identity4 = safeDirectory(directory2), file2 = join38(directory2, "operation.lock");
45428
+ const identity4 = safeDirectory(directory2), file2 = join39(directory2, "operation.lock");
45220
45429
  let fd;
45221
45430
  try {
45222
45431
  fd = openSync13(file2, constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
@@ -45232,7 +45441,7 @@ async function locked(directory2, action) {
45232
45441
  } finally {
45233
45442
  closeSync13(fd);
45234
45443
  unchangedDirectory(directory2, identity4);
45235
- const now = lstatSync23(file2);
45444
+ const now = lstatSync24(file2);
45236
45445
  if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
45237
45446
  fail2();
45238
45447
  unlinkSync5(file2);
@@ -45284,7 +45493,7 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
45284
45493
  phase: "prepared",
45285
45494
  intent: null
45286
45495
  };
45287
- if (!isAbsolute20(recoveryDirectory) || resolve20(recoveryDirectory) !== recoveryDirectory || realpathSync10(dirname26(recoveryDirectory)) !== dirname26(recoveryDirectory))
45496
+ if (!isAbsolute20(recoveryDirectory) || resolve21(recoveryDirectory) !== recoveryDirectory || realpathSync11(dirname26(recoveryDirectory)) !== dirname26(recoveryDirectory))
45288
45497
  return fail2();
45289
45498
  mkdirSync18(recoveryDirectory, { mode: 448 });
45290
45499
  safeDirectory(recoveryDirectory);
@@ -45376,7 +45585,7 @@ async function inspectLocked(client2, directory2, cancel) {
45376
45585
  }
45377
45586
  // src/lib/skill-context.ts
45378
45587
  import { createHash as createHash26 } from "crypto";
45379
- import { resolve as resolve21 } from "path";
45588
+ import { resolve as resolve22 } from "path";
45380
45589
  function words(value) {
45381
45590
  return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
45382
45591
  }
@@ -45398,7 +45607,11 @@ async function buildSkillContext(input2, options = {}) {
45398
45607
  }
45399
45608
  const profileId = input2.profileId ?? "default";
45400
45609
  const sessionId = input2.sessionId ? input2.agentId ? `${input2.sessionId}:${input2.agentId}` : input2.sessionId : undefined;
45401
- const resolverOptions = { ...options, projectDir: input2.cwd ?? options.projectDir, sessionId, parentSessionId: input2.agentId ? input2.sessionId : undefined };
45610
+ if (input2.parentSessionId !== undefined) {
45611
+ if (input2.agentId !== undefined || !sessionId || input2.parentSessionId === sessionId || input2.parentSessionId !== null && (typeof input2.parentSessionId !== "string" || !input2.parentSessionId.trim()))
45612
+ throw new SkillSelectionError("INVALID_SESSION", "Native session custody requires its own session id and a distinct parent, without a legacy agent id.");
45613
+ }
45614
+ const resolverOptions = { ...options, projectDir: input2.cwd ?? options.projectDir, sessionId, nativeParentSessionId: input2.parentSessionId, parentSessionId: input2.parentSessionId ?? (input2.agentId ? input2.sessionId : undefined) };
45402
45615
  const resolved = await resolveSelectionContext(profileId, resolverOptions);
45403
45616
  const profile = resolved.receipt.profile;
45404
45617
  const explicit = new Set((input2.skills ?? []).map((spec) => selectionKey(exactProfileSelection(spec, profile))));
@@ -45411,7 +45624,7 @@ async function buildSkillContext(input2, options = {}) {
45411
45624
  const promptWords = words(prompt);
45412
45625
  const promptNames = new Set(prompt.toLowerCase().match(/[a-z0-9]+(?:-[a-z0-9]+)*/g) ?? []);
45413
45626
  const loaded = new Set(resolved.session?.loaded ?? []);
45414
- const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd, resolve21(input2.cwd)] : []];
45627
+ const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd, resolve22(input2.cwd)] : []];
45415
45628
  const candidates = profile.selections.map((selection) => {
45416
45629
  const key = selectionKey(selection);
45417
45630
  if (input2.restore && loaded.has(key))