@hasna/skills 0.10.44 → 0.10.46

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/bin/index.js CHANGED
@@ -36868,7 +36868,7 @@ var package_default;
36868
36868
  var init_package = __esm(() => {
36869
36869
  package_default = {
36870
36870
  name: "@hasna/skills",
36871
- version: "0.10.44",
36871
+ version: "0.10.46",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -39885,8 +39885,348 @@ var init_agent_adapters = __esm(() => {
39885
39885
  };
39886
39886
  });
39887
39887
 
39888
+ // src/lib/claude-settings-witness.ts
39889
+ import { createHash as createHash2 } from "crypto";
39890
+ import { closeSync, constants as constants2, fstatSync, lstatSync as lstatSync3, openSync, readSync } from "fs";
39891
+ import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, resolve as resolve3 } from "path";
39892
+ function need(value, reason) {
39893
+ if (!value)
39894
+ throw new Error(`Claude settings witness ${reason}`);
39895
+ }
39896
+ function absolutePath(value) {
39897
+ need(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute2(value) && resolve3(value) === value, "requires a normalized absolute path");
39898
+ }
39899
+ function parents(path) {
39900
+ const result2 = [];
39901
+ for (let at2 = dirname3(path);; at2 = dirname3(at2)) {
39902
+ const stat = lstatSync3(at2, { bigint: true });
39903
+ need(stat.isDirectory() && !stat.isSymbolicLink(), "path traverses a symlink or non-directory");
39904
+ result2.push([at2, stat]);
39905
+ if (at2 === dirname3(at2))
39906
+ return result2;
39907
+ }
39908
+ }
39909
+ function readNativeSettingsWitnessFile(path, budget, filename = "settings.json") {
39910
+ absolutePath(path);
39911
+ need(basename2(path) === filename, `requires ${filename}`);
39912
+ need(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
39913
+ const ancestors = parents(path), initial2 = lstatSync3(path, { bigint: true });
39914
+ need(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_SETTINGS_WITNESS_LIMITS.bytes), "is not a bounded regular file");
39915
+ need(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
39916
+ const fd = openSync(path, constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK);
39917
+ try {
39918
+ const opened = fstatSync(fd, { bigint: true });
39919
+ need(opened.isFile() && sameFile(initial2, opened), "changed during open");
39920
+ const bytes = Buffer.alloc(Number(opened.size) + 1);
39921
+ let length = 0;
39922
+ while (length < bytes.length) {
39923
+ const count = readSync(fd, bytes, length, bytes.length - length, null);
39924
+ if (!count)
39925
+ break;
39926
+ length += count;
39927
+ }
39928
+ const after2 = fstatSync(fd, { bigint: true }), current = lstatSync3(path, { bigint: true });
39929
+ need(current.isFile() && sameFile(opened, after2) && sameFile(after2, current) && BigInt(length) === opened.size, "changed during read");
39930
+ for (const [ancestor, before2] of ancestors) {
39931
+ const now3 = lstatSync3(ancestor, { bigint: true });
39932
+ need(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
39933
+ }
39934
+ budget.remaining -= length;
39935
+ try {
39936
+ return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
39937
+ } catch {
39938
+ throw new Error("Claude settings witness is not strict UTF-8");
39939
+ }
39940
+ } finally {
39941
+ closeSync(fd);
39942
+ }
39943
+ }
39944
+ function parse(text) {
39945
+ let at2 = 0, nodes = 0;
39946
+ const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
39947
+ const space = () => {
39948
+ while (at2 < text.length && /[\x20\t\r\n]/.test(text[at2]))
39949
+ at2++;
39950
+ };
39951
+ function string() {
39952
+ need(text[at2] === '"', "contains invalid JSON");
39953
+ const start = at2++;
39954
+ while (at2 < text.length) {
39955
+ const character = text[at2++];
39956
+ if (character === '"') {
39957
+ let value2;
39958
+ try {
39959
+ value2 = JSON.parse(text.slice(start, at2));
39960
+ } catch {
39961
+ throw new Error("Claude settings witness contains invalid JSON string");
39962
+ }
39963
+ need(value2.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.stringCharacters, "exceeds its string limit");
39964
+ return value2;
39965
+ }
39966
+ if (character === "\\")
39967
+ at2++;
39968
+ }
39969
+ throw new Error("Claude settings witness contains an unterminated JSON string");
39970
+ }
39971
+ function value(depth) {
39972
+ need(depth <= CLAUDE_SETTINGS_WITNESS_LIMITS.depth && ++nodes <= CLAUDE_SETTINGS_WITNESS_LIMITS.nodes, "exceeds its nesting or node limit");
39973
+ space();
39974
+ const character = text[at2];
39975
+ if (character === '"')
39976
+ return { kind: "string", value: string() };
39977
+ if (character === "{" || character === "[") {
39978
+ at2++;
39979
+ space();
39980
+ const object = character === "{", end = object ? "}" : "]", entries = [], items = [], keys2 = new Set;
39981
+ if (text[at2] !== end)
39982
+ while (true) {
39983
+ if (object) {
39984
+ space();
39985
+ const key = string();
39986
+ need(!keys2.has(key), "contains a duplicate JSON key");
39987
+ keys2.add(key);
39988
+ space();
39989
+ need(text[at2++] === ":", "contains invalid JSON");
39990
+ entries.push([key, value(depth + 1)]);
39991
+ } else
39992
+ items.push(value(depth + 1));
39993
+ space();
39994
+ if (text[at2] === end)
39995
+ break;
39996
+ need(text[at2++] === ",", "contains invalid JSON");
39997
+ }
39998
+ at2++;
39999
+ return object ? { kind: "object", entries } : { kind: "array", items };
40000
+ }
40001
+ for (const literal of ["true", "false", "null"])
40002
+ if (text.startsWith(literal, at2)) {
40003
+ at2 += literal.length;
40004
+ return { kind: "literal", value: literal };
40005
+ }
40006
+ numberPattern.lastIndex = at2;
40007
+ const number = numberPattern.exec(text);
40008
+ need(number, "contains invalid JSON");
40009
+ at2 += number[0].length;
40010
+ return { kind: "number", value: number[0] };
40011
+ }
40012
+ const root = value(0);
40013
+ space();
40014
+ need(at2 === text.length && root.kind === "object", "requires a JSON object without trailing content");
40015
+ need(root.entries.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.rows, "exceeds its settings field limit");
40016
+ return root;
40017
+ }
40018
+ function canonical(value) {
40019
+ if (value.kind === "object")
40020
+ return { kind: "object", entries: value.entries.map(([key, child]) => [key, canonical(child)]).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0) };
40021
+ if (value.kind === "array")
40022
+ return { kind: "array", items: value.items.map(canonical) };
40023
+ return value;
40024
+ }
40025
+ function inferencePreference(key, child, version) {
40026
+ if (key === "skipDangerousModePermissionPrompt") {
40027
+ need(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid dialog acknowledgment");
40028
+ return false;
40029
+ }
40030
+ if (key === "effortLevel") {
40031
+ need(child.kind === "string" && PERSISTED_EFFORT_LEVELS.has(child.value), "contains an invalid persisted effort level");
40032
+ return true;
40033
+ }
40034
+ if (key !== "modelSettings")
40035
+ return false;
40036
+ need(child.kind === "object", "requires an object of model preferences");
40037
+ child.entries = child.entries.filter(([model, preferences]) => {
40038
+ if (version === 2 && !BUILTIN_MODEL_SELECTIONS.has(model) || preferences.kind !== "object" || preferences.entries.length !== 1 || preferences.entries[0][0] !== "effortLevel")
40039
+ return true;
40040
+ const effort = preferences.entries[0][1];
40041
+ need(effort.kind === "string" && PERSISTED_EFFORT_LEVELS.has(effort.value), "contains an invalid persisted model effort level");
40042
+ return false;
40043
+ });
40044
+ return child.entries.length === 0;
40045
+ }
40046
+ function settingsDigest(text, version = 1) {
40047
+ const value = parse(text);
40048
+ value.entries = value.entries.filter(([key, child]) => {
40049
+ if (version !== 1 && inferencePreference(key, child, version))
40050
+ return false;
40051
+ if (key === "model") {
40052
+ need(child.kind === "string", "contains an invalid model selection");
40053
+ return !BUILTIN_MODEL_SELECTIONS.has(child.value);
40054
+ }
40055
+ if (BOOLEAN_PREFERENCES.has(key)) {
40056
+ need(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid display preference");
40057
+ return false;
40058
+ }
40059
+ if (Object.hasOwn(ENUM_PREFERENCES, key)) {
40060
+ need(child.kind === "string" && ENUM_PREFERENCES[key].includes(child.value), "contains an invalid display preference");
40061
+ return false;
40062
+ }
40063
+ return true;
40064
+ });
40065
+ return createHash2("sha256").update(`hasna.skills.claude-settings.v${version}\x00`).update(JSON.stringify(canonical(value))).digest("hex");
40066
+ }
40067
+ function hashClaudeSettingsReplacement(text, budget) {
40068
+ need(typeof text === "string", "requires settings text");
40069
+ const bytes = Buffer.byteLength(text);
40070
+ need(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
40071
+ budget.remaining -= bytes;
40072
+ return settingsDigest(text);
40073
+ }
40074
+ function captureClaudeSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
40075
+ return { path, hashMode: "claude-settings-v1", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget)) };
40076
+ }
40077
+ function captureClaudeSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
40078
+ return { path, hashMode: "claude-settings-v2", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 2) };
40079
+ }
40080
+ function hashClaudeSettingsReplacementV2(text, budget) {
40081
+ need(typeof text === "string", "requires settings text");
40082
+ const bytes = Buffer.byteLength(text);
40083
+ need(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
40084
+ budget.remaining -= bytes;
40085
+ return settingsDigest(text, 2);
40086
+ }
40087
+ function captureClaudeSettingsV3(path, budget = { remaining: 256 * 1024 * 1024 }) {
40088
+ return { path, hashMode: "claude-settings-v3", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 3) };
40089
+ }
40090
+ function hashClaudeSettingsReplacementV3(text, budget) {
40091
+ need(typeof text === "string", "requires settings text");
40092
+ const bytes = Buffer.byteLength(text);
40093
+ need(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
40094
+ budget.remaining -= bytes;
40095
+ return settingsDigest(text, 3);
40096
+ }
40097
+ function upgradeClaudeSettingsWitness(previous, reviewedSettingsPath) {
40098
+ need(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes" || previous.hashMode === "claude-settings-v1" || previous.hashMode === "claude-settings-v2") && typeof previous.sha256 === "string" && /^[a-f0-9]{64}$/.test(previous.sha256), "requires an exact legacy settings witness");
40099
+ const budget = { remaining: 2 * CLAUDE_SETTINGS_WITNESS_LIMITS.bytes };
40100
+ const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget), current = readNativeSettingsWitnessFile(previous.path, budget);
40101
+ const beforeDigest = previous.hashMode === undefined || previous.hashMode === "bytes" ? createHash2("sha256").update(before2).digest("hex") : settingsDigest(before2, previous.hashMode === "claude-settings-v1" ? 1 : 2);
40102
+ need(beforeDigest === previous.sha256, "reviewed preimage does not match the legacy witness");
40103
+ const sha256 = settingsDigest(current, 3);
40104
+ need(settingsDigest(before2, 3) === sha256, "non-preference settings changed; explicit discovery review required");
40105
+ return { path: previous.path, hashMode: "claude-settings-v3", sha256 };
40106
+ }
40107
+ function hashNativeJsonControls(text, excludedMetadata) {
40108
+ need(Buffer.byteLength(text) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
40109
+ const value = parse(text);
40110
+ value.entries = value.entries.filter(([key, child]) => {
40111
+ if (key !== excludedMetadata)
40112
+ return true;
40113
+ need(child.kind === "string" && child.value.length <= 128, "has invalid version metadata");
40114
+ return false;
40115
+ });
40116
+ return createHash2("sha256").update("hasna.skills.native-json-controls.v1\x00").update(JSON.stringify(canonical(value))).digest("hex");
40117
+ }
40118
+ function hashSumiNativeJsonControls(text) {
40119
+ need(Buffer.byteLength(text) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
40120
+ const value = parse(text);
40121
+ value.entries = value.entries.filter(([key, child]) => {
40122
+ if (key === "$schema" || key === "username") {
40123
+ need(child.kind === "string", "has invalid Sumi display metadata");
40124
+ return false;
40125
+ }
40126
+ if (key !== "experimental")
40127
+ return true;
40128
+ need(child.kind === "object", "requires Sumi experimental controls to be an object");
40129
+ child.entries = child.entries.filter(([name, option]) => {
40130
+ if (name !== "statusline" && name !== "compact_tools")
40131
+ return true;
40132
+ need(option.kind === "literal" && (option.value === "true" || option.value === "false"), "has invalid Sumi display preference");
40133
+ return false;
40134
+ });
40135
+ return child.entries.length > 0;
40136
+ });
40137
+ return createHash2("sha256").update("hasna.skills.sumi-settings.v1\x00").update(JSON.stringify(value)).digest("hex");
40138
+ }
40139
+ var CLAUDE_SETTINGS_WITNESS_LIMITS, sameFile = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, BOOLEAN_PREFERENCES, ENUM_PREFERENCES, BUILTIN_MODEL_SELECTIONS, PERSISTED_EFFORT_LEVELS;
40140
+ var init_claude_settings_witness = __esm(() => {
40141
+ CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
40142
+ BOOLEAN_PREFERENCES = new Set([
40143
+ "autoScrollEnabled",
40144
+ "axScreenReader",
40145
+ "emojiCompletionEnabled",
40146
+ "prefersReducedMotion",
40147
+ "showTurnDuration",
40148
+ "spinnerTipsEnabled",
40149
+ "syntaxHighlightingDisabled",
40150
+ "terminalProgressBarEnabled",
40151
+ "terminalTitleFromRename",
40152
+ "verbose",
40153
+ "wheelScrollAccelerationEnabled"
40154
+ ]);
40155
+ ENUM_PREFERENCES = Object.freeze({
40156
+ editorMode: ["normal", "vim"],
40157
+ tui: ["default", "fullscreen"],
40158
+ viewMode: ["default", "verbose", "focus"]
40159
+ });
40160
+ BUILTIN_MODEL_SELECTIONS = new Set([
40161
+ "default",
40162
+ "best",
40163
+ "fable",
40164
+ "fable[1m]",
40165
+ "sonnet",
40166
+ "sonnet[1m]",
40167
+ "opus",
40168
+ "opus[1m]",
40169
+ "haiku",
40170
+ "opusplan",
40171
+ "claude-fable-5-1",
40172
+ "claude-fable-5",
40173
+ "claude-fable-5[1m]",
40174
+ "claude-opus-5",
40175
+ "claude-sonnet-5",
40176
+ "claude-haiku-4-5-20251001",
40177
+ "claude-opus-4-6",
40178
+ "claude-sonnet-4-5",
40179
+ "claude-sonnet-4-5-20250929",
40180
+ "claude-opus-4-8",
40181
+ "claude-opus-4-8[1m]",
40182
+ "claude-opus-4-7",
40183
+ "claude-sonnet-4-6",
40184
+ "claude-opus-4-5-20251101",
40185
+ "claude-opus-4-5",
40186
+ "claude-haiku-4-5",
40187
+ "claude-fable-5-1[1m]",
40188
+ "claude-opus-5[1m]",
40189
+ "claude-opus-4-7[1m]",
40190
+ "claude-opus-4-6[1m]",
40191
+ "claude-sonnet-4-6[1m]"
40192
+ ]);
40193
+ PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
40194
+ });
40195
+
40196
+ // src/lib/sumi-settings-witness.ts
40197
+ import { createHash as createHash3 } from "crypto";
40198
+ function readSumiSettingsPreimage(path) {
40199
+ return readNativeSettingsWitnessFile(path, budget(), "sumi.json");
40200
+ }
40201
+ function hashSumiSettingsReplacement(text, limits) {
40202
+ const bytes = Buffer.byteLength(text);
40203
+ if (bytes > CLAUDE_SETTINGS_WITNESS_LIMITS.bytes || !Number.isSafeInteger(limits.remaining) || limits.remaining < bytes)
40204
+ throw new Error("Sumi settings witness exceeds its byte limit");
40205
+ limits.remaining -= bytes;
40206
+ return hashSumiNativeJsonControls(text);
40207
+ }
40208
+ function captureSumiSettings(path, limits = budget()) {
40209
+ return { path, hashMode: "sumi-settings-v1", sha256: hashSumiNativeJsonControls(readNativeSettingsWitnessFile(path, limits, "sumi.json")) };
40210
+ }
40211
+ function upgradeSumiSettingsWitness(previous, reviewedSettingsPath) {
40212
+ if (!previous || Object.keys(previous).some((key) => !["path", "hashMode", "sha256"].includes(key)) || ![undefined, "bytes"].includes(previous.hashMode) || !/^[a-f0-9]{64}$/.test(previous.sha256))
40213
+ throw new Error("Sumi settings upgrade requires one exact preserved byte witness");
40214
+ const before2 = readSumiSettingsPreimage(reviewedSettingsPath);
40215
+ if (createHash3("sha256").update(before2).digest("hex") !== previous.sha256)
40216
+ throw new Error("Reviewed Sumi preimage does not match its byte witness");
40217
+ const next = captureSumiSettings(previous.path);
40218
+ if (hashSumiNativeJsonControls(before2) !== next.sha256)
40219
+ throw new Error("Sumi non-display settings changed; explicit discovery review required");
40220
+ return next;
40221
+ }
40222
+ var SUMI_DISCOVERY_PROJECTION_FIELDS, budget = () => ({ remaining: 256 * 1024 * 1024 });
40223
+ var init_sumi_settings_witness = __esm(() => {
40224
+ init_claude_settings_witness();
40225
+ SUMI_DISCOVERY_PROJECTION_FIELDS = ["skills", "plugin", "plugins", "permissions"];
40226
+ });
40227
+
39888
40228
  // src/lib/agent-policy-limits.ts
39889
- import { basename as basename2, isAbsolute as isAbsolute2, resolve as resolve3 } from "path";
40229
+ import { basename as basename3, isAbsolute as isAbsolute3, resolve as resolve4 } from "path";
39890
40230
  function object(value) {
39891
40231
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
39892
40232
  }
@@ -39939,7 +40279,7 @@ function assertAgentPolicyCollections(policy) {
39939
40279
  text(control.pluginId, 1024);
39940
40280
  text(control.namespace, 64);
39941
40281
  text(control.pluginParent);
39942
- requireBound(isAbsolute2(control.pluginParent) && resolve3(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
40282
+ requireBound(isAbsolute3(control.pluginParent) && resolve4(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
39943
40283
  if (control.remotePluginId !== undefined)
39944
40284
  requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
39945
40285
  if (control.skillsOnly !== undefined)
@@ -39957,7 +40297,7 @@ function assertAgentPolicyCollections(policy) {
39957
40297
  text(control.pluginId, 1024);
39958
40298
  text(control.namespace, 64);
39959
40299
  text(control.pluginParent);
39960
- requireBound(!ids.has(control.pluginId) && isAbsolute2(control.pluginParent) && resolve3(control.pluginParent) === control.pluginParent && ["local", "git", "npm"].includes(control.sourceType) && typeof control.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(control.sourceSha256));
40300
+ requireBound(!ids.has(control.pluginId) && isAbsolute3(control.pluginParent) && resolve4(control.pluginParent) === control.pluginParent && ["local", "git", "npm"].includes(control.sourceType) && typeof control.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(control.sourceSha256));
39961
40301
  ids.add(control.pluginId);
39962
40302
  }
39963
40303
  }
@@ -39982,15 +40322,15 @@ function assertAgentPolicyCollections(policy) {
39982
40322
  requireBound(object(value));
39983
40323
  text(value.agent, 128);
39984
40324
  if (value.codexRetiredMaterializations !== undefined) {
39985
- const proof = record(value.codexRetiredMaterializations, 3), roots = array(proof.roots, AGENT_POLICY_LIMITS.discoveryRoots), parents = proof.parents === undefined ? [] : array(proof.parents, AGENT_POLICY_LIMITS.discoveryRoots);
39986
- requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && Object.keys(proof).every((key) => ["roots", "parents", "directories"].includes(key)) && roots.length + parents.length > 0 && new Set(roots).size === roots.length && new Set(parents).size === parents.length);
40325
+ const proof = record(value.codexRetiredMaterializations, 3), roots = array(proof.roots, AGENT_POLICY_LIMITS.discoveryRoots), parents2 = proof.parents === undefined ? [] : array(proof.parents, AGENT_POLICY_LIMITS.discoveryRoots);
40326
+ requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && Object.keys(proof).every((key) => ["roots", "parents", "directories"].includes(key)) && roots.length + parents2.length > 0 && new Set(roots).size === roots.length && new Set(parents2).size === parents2.length);
39987
40327
  for (const root of roots) {
39988
40328
  text(root);
39989
- requireBound(isAbsolute2(root) && resolve3(root) === root);
40329
+ requireBound(isAbsolute3(root) && resolve4(root) === root);
39990
40330
  }
39991
- for (const parent of parents) {
40331
+ for (const parent of parents2) {
39992
40332
  text(parent);
39993
- requireBound(isAbsolute2(parent) && resolve3(parent) === parent);
40333
+ requireBound(isAbsolute3(parent) && resolve4(parent) === parent);
39994
40334
  }
39995
40335
  for (const directory of array(proof.directories, AGENT_POLICY_LIMITS.discoveryDirectories)) {
39996
40336
  requireBound(object(directory));
@@ -40010,7 +40350,7 @@ function assertAgentPolicyCollections(policy) {
40010
40350
  text(input.namespace, 64);
40011
40351
  text(input.pluginParent);
40012
40352
  text(input.sourceRoot);
40013
- requireBound(!ids.has(input.pluginId) && [input.pluginParent, input.sourceRoot].every((path) => isAbsolute2(path) && resolve3(path) === path) && typeof input.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(input.sourceSha256));
40353
+ requireBound(!ids.has(input.pluginId) && [input.pluginParent, input.sourceRoot].every((path) => isAbsolute3(path) && resolve4(path) === path) && typeof input.sourceSha256 === "string" && /^[a-f0-9]{64}$/.test(input.sourceSha256));
40014
40354
  ids.add(input.pluginId);
40015
40355
  }
40016
40356
  if (proof.directories !== undefined)
@@ -40027,13 +40367,15 @@ function assertAgentPolicyCollections(policy) {
40027
40367
  text(source.path);
40028
40368
  requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
40029
40369
  if (source.hashMode !== undefined)
40030
- requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
40370
+ requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
40371
+ if (source.hashMode === "sumi-settings-v1")
40372
+ requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve4(source.path) === source.path && basename3(source.path) === "sumi.json");
40031
40373
  if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
40032
- requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "config.toml");
40374
+ requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve4(source.path) === source.path && basename3(source.path) === "config.toml");
40033
40375
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
40034
- requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "settings.json");
40376
+ requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve4(source.path) === source.path && basename3(source.path) === "settings.json");
40035
40377
  if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2")
40036
- requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "known_marketplaces.json");
40378
+ requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve4(source.path) === source.path && basename3(source.path) === "known_marketplaces.json");
40037
40379
  if (source.hashMode === "claude-plugin-registry") {
40038
40380
  requireBound(agent === "claude");
40039
40381
  const managed = array(source.managedPlugins, 64);
@@ -46961,7 +47303,7 @@ var require_public_api = __commonJS((exports) => {
46961
47303
  }
46962
47304
  return doc;
46963
47305
  }
46964
- function parse(src, reviver, options) {
47306
+ function parse2(src, reviver, options) {
46965
47307
  let _reviver = undefined;
46966
47308
  if (typeof reviver === "function") {
46967
47309
  _reviver = reviver;
@@ -47002,7 +47344,7 @@ var require_public_api = __commonJS((exports) => {
47002
47344
  return value.toString(options);
47003
47345
  return new Document.Document(value, _replacer, options).toString(options);
47004
47346
  }
47005
- exports.parse = parse;
47347
+ exports.parse = parse2;
47006
47348
  exports.parseAllDocuments = parseAllDocuments;
47007
47349
  exports.parseDocument = parseDocument;
47008
47350
  exports.stringify = stringify;
@@ -47058,8 +47400,8 @@ var init_dist = __esm(() => {
47058
47400
  });
47059
47401
 
47060
47402
  // src/lib/agent-hermes.ts
47061
- import { dirname as dirname3, isAbsolute as isAbsolute3, join as join11, resolve as resolve4 } from "path";
47062
- import { lstatSync as lstatSync3, readFileSync as readFileSync7, opendirSync } from "fs";
47403
+ import { dirname as dirname4, isAbsolute as isAbsolute4, join as join11, resolve as resolve5 } from "path";
47404
+ import { lstatSync as lstatSync4, readFileSync as readFileSync7, opendirSync } from "fs";
47063
47405
  function object2(value) {
47064
47406
  return Boolean(value && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null));
47065
47407
  }
@@ -47094,7 +47436,7 @@ function quoted(value) {
47094
47436
  return `'${value.replace(/'/g, `'\\''`)}'`;
47095
47437
  }
47096
47438
  function hermesHookDefinitions(supervisor) {
47097
- if (!isAbsolute3(supervisor.runtime) || !isAbsolute3(supervisor.path))
47439
+ if (!isAbsolute4(supervisor.runtime) || !isAbsolute4(supervisor.path))
47098
47440
  throw new Error("Expected absolute Hermes supervisor paths");
47099
47441
  const entry = (event) => ({ command: `${quoted(supervisor.runtime)} ${quoted(supervisor.path)} --event ${event}`, timeout: 15, ...event === "pre_tool_call" ? { fail_closed: true } : {} });
47100
47442
  return { pre_llm_call: entry("pre_llm_call"), pre_tool_call: entry("pre_tool_call") };
@@ -47130,19 +47472,19 @@ function assertHermesEnvironment(home) {
47130
47472
  throw new Error(`NATIVE_SKILL_DRIFT: Hermes ${variable} requires a dedicated discovery adapter; unset it before using this adapter`);
47131
47473
  }
47132
47474
  const selected = process.env.HERMES_HOME?.trim();
47133
- if (selected && (!isAbsolute3(selected) || resolve4(selected) !== join11(resolve4(home), ".hermes")))
47475
+ if (selected && (!isAbsolute4(selected) || resolve5(selected) !== join11(resolve5(home), ".hermes")))
47134
47476
  throw new Error("NATIVE_SKILL_DRIFT: custom Hermes homes/profiles require their own reviewed bridge");
47135
47477
  if (process.env.HERMES_ENABLE_PROJECT_PLUGINS?.trim() && !["0", "false", "no", "off"].includes(process.env.HERMES_ENABLE_PROJECT_PLUGINS.trim().toLowerCase()))
47136
47478
  throw new Error("NATIVE_SKILL_DRIFT: Hermes project plugins require a dedicated discovery review");
47137
47479
  }
47138
47480
  function read(path) {
47139
- for (let current = path;; current = dirname3(current)) {
47140
- if (lstatSync3(current, { throwIfNoEntry: false })?.isSymbolicLink())
47481
+ for (let current = path;; current = dirname4(current)) {
47482
+ if (lstatSync4(current, { throwIfNoEntry: false })?.isSymbolicLink())
47141
47483
  throw new Error("NATIVE_SKILL_DRIFT: symlink Hermes protection input");
47142
- if (dirname3(current) === current)
47484
+ if (dirname4(current) === current)
47143
47485
  break;
47144
47486
  }
47145
- const stat = lstatSync3(path, { throwIfNoEntry: false });
47487
+ const stat = lstatSync4(path, { throwIfNoEntry: false });
47146
47488
  if (!stat)
47147
47489
  return null;
47148
47490
  if (!stat.isFile() || stat.size > 1024 * 1024)
@@ -47153,7 +47495,7 @@ function assertHermesProtection(home, config, command, profile, supervisor) {
47153
47495
  assertHermesEnvironment(home);
47154
47496
  if (read(join11(home, ".hermes", HERMES_OPT_OUT)) === null)
47155
47497
  throw new Error("NATIVE_SKILL_DRIFT: Hermes bundled skill reseeding is not disabled; run skills hook install");
47156
- if (!supervisor || !isAbsolute3(supervisor.path) || supervisor.runtime !== process.execPath || read(supervisor.path) !== renderHermesSupervisor(command, profile))
47498
+ if (!supervisor || !isAbsolute4(supervisor.path) || supervisor.runtime !== process.execPath || read(supervisor.path) !== renderHermesSupervisor(command, profile))
47157
47499
  throw new Error("NATIVE_SKILL_DRIFT: Hermes owned supervisor changed; run skills hook install");
47158
47500
  const raw = read(join11(home, ".hermes/shell-hooks-allowlist.json"));
47159
47501
  let trust;
@@ -47179,16 +47521,16 @@ function assertHermesProtection(home, config, command, profile, supervisor) {
47179
47521
  }
47180
47522
  function assertNoHermesLegacyShadow(root) {
47181
47523
  let entries = 0;
47182
- for (let cursor = resolve4(root);; cursor = dirname3(cursor)) {
47183
- if (lstatSync3(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
47524
+ for (let cursor = resolve5(root);; cursor = dirname4(cursor)) {
47525
+ if (lstatSync4(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
47184
47526
  throw new Error("NATIVE_SKILL_DRIFT: symlink Hermes legacy discovery root");
47185
- if (dirname3(cursor) === cursor)
47527
+ if (dirname4(cursor) === cursor)
47186
47528
  break;
47187
47529
  }
47188
47530
  function scan(path, depth) {
47189
47531
  if (++entries > 1e4 || depth > 64)
47190
47532
  throw new Error("NATIVE_SKILL_DRIFT: Hermes legacy discovery limit exceeded; review the root before continuing");
47191
- const stat = lstatSync3(path, { throwIfNoEntry: false });
47533
+ const stat = lstatSync4(path, { throwIfNoEntry: false });
47192
47534
  if (!stat)
47193
47535
  return;
47194
47536
  if (stat.isSymbolicLink())
@@ -47198,9 +47540,9 @@ function assertNoHermesLegacyShadow(root) {
47198
47540
  throw new Error("NATIVE_SKILL_DRIFT: unsupported Hermes legacy discovery input");
47199
47541
  return;
47200
47542
  }
47201
- if (lstatSync3(join11(path, "skills-cli.md"), { throwIfNoEntry: false }))
47543
+ if (lstatSync4(join11(path, "skills-cli.md"), { throwIfNoEntry: false }))
47202
47544
  throw new Error("NATIVE_SKILL_DRIFT: legacy Hermes skills-cli.md can shadow the owned bridge; preserve and retire it before continuing");
47203
- const hasDescriptor = Boolean(lstatSync3(join11(path, "SKILL.md"), { throwIfNoEntry: false }));
47545
+ const hasDescriptor = Boolean(lstatSync4(join11(path, "SKILL.md"), { throwIfNoEntry: false }));
47204
47546
  const directory = opendirSync(path);
47205
47547
  try {
47206
47548
  for (let child = directory.readSync();child; child = directory.readSync()) {
@@ -47281,189 +47623,189 @@ var init_agent_hermes = __esm(() => {
47281
47623
  });
47282
47624
 
47283
47625
  // src/lib/agent-discovery-directories.ts
47284
- import { createHash as createHash2 } from "crypto";
47285
- import { lstatSync as lstatSync4, opendirSync as opendirSync2 } from "fs";
47286
- import { dirname as dirname4, isAbsolute as isAbsolute4, join as join12, resolve as resolve5 } from "path";
47287
- function need(value, message) {
47626
+ import { createHash as createHash4 } from "crypto";
47627
+ import { lstatSync as lstatSync5, opendirSync as opendirSync2 } from "fs";
47628
+ import { dirname as dirname5, isAbsolute as isAbsolute5, join as join12, resolve as resolve6 } from "path";
47629
+ function need2(value, message) {
47288
47630
  if (!value)
47289
47631
  throw new Error(message);
47290
47632
  }
47291
47633
  function safe(path) {
47292
- need(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute4(path) && resolve5(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
47293
- for (let cursor = path;; cursor = dirname4(cursor)) {
47294
- need(!lstatSync4(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
47295
- if (dirname4(cursor) === cursor)
47634
+ need2(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute5(path) && resolve6(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
47635
+ for (let cursor = path;; cursor = dirname5(cursor)) {
47636
+ need2(!lstatSync5(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
47637
+ if (dirname5(cursor) === cursor)
47296
47638
  break;
47297
47639
  }
47298
47640
  }
47299
47641
  function same(before2, after2) {
47300
47642
  return Boolean(after2 && after2.isDirectory() && before2.dev === after2.dev && before2.ino === after2.ino && before2.mtimeMs === after2.mtimeMs && before2.ctimeMs === after2.ctimeMs);
47301
47643
  }
47302
- function capture(path, budget, excludedRoots, omittedRoots = [], rows) {
47644
+ function capture(path, budget2, excludedRoots, omittedRoots = [], rows) {
47303
47645
  safe(path);
47304
47646
  if (omittedRoots.some((root2) => path === root2 || path.startsWith(root2 + "/")))
47305
47647
  return { path, sha256: null };
47306
- const root = lstatSync4(path, { throwIfNoEntry: false });
47648
+ const root = lstatSync5(path, { throwIfNoEntry: false });
47307
47649
  if (!root)
47308
47650
  return { path, sha256: null };
47309
- need(root.isDirectory(), "Unsupported native discovery directory input");
47310
- const hash = createHash2("sha256");
47651
+ need2(root.isDirectory(), "Unsupported native discovery directory input");
47652
+ const hash = createHash4("sha256");
47311
47653
  function walk(current, relative2, before2, depth) {
47312
- need(depth <= 64, "Native discovery directory depth limit exceeded");
47654
+ need2(depth <= 64, "Native discovery directory depth limit exceeded");
47313
47655
  const names = [], directory = opendirSync2(current);
47314
47656
  try {
47315
47657
  for (let entry = directory.readSync();entry; entry = directory.readSync()) {
47316
- need(++budget.entries <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Native discovery directory entry limit exceeded");
47658
+ need2(++budget2.entries <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Native discovery directory entry limit exceeded");
47317
47659
  names.push(entry.name);
47318
47660
  }
47319
47661
  } finally {
47320
47662
  directory.closeSync();
47321
47663
  }
47322
- need(new Set(names).size === names.length, "Ambiguous native discovery directory names");
47664
+ need2(new Set(names).size === names.length, "Ambiguous native discovery directory names");
47323
47665
  for (const name of names.sort()) {
47324
47666
  const child = join12(current, name), childRelative = relative2 ? `${relative2}/${name}` : name;
47325
47667
  if (omittedRoots.includes(child))
47326
47668
  continue;
47327
- need(child.length <= AGENT_POLICY_LIMITS.pathCharacters, "Native discovery directory path limit exceeded");
47328
- const stat = lstatSync4(child);
47329
- need(stat.isFile() || stat.isDirectory(), "Refusing symlink or special native discovery directory member");
47669
+ need2(child.length <= AGENT_POLICY_LIMITS.pathCharacters, "Native discovery directory path limit exceeded");
47670
+ const stat = lstatSync5(child);
47671
+ need2(stat.isFile() || stat.isDirectory(), "Refusing symlink or special native discovery directory member");
47330
47672
  const row = JSON.stringify([childRelative, stat.isDirectory() ? "directory" : "file"]) + `
47331
47673
  `;
47332
- budget.bytes += Buffer.byteLength(row);
47333
- need(budget.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
47674
+ budget2.bytes += Buffer.byteLength(row);
47675
+ need2(budget2.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
47334
47676
  hash.update(row);
47335
47677
  rows?.push(row);
47336
47678
  if (stat.isDirectory() && !excludedRoots.includes(child))
47337
47679
  walk(child, childRelative, stat, depth + 1);
47338
47680
  }
47339
- need(same(before2, lstatSync4(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
47681
+ need2(same(before2, lstatSync5(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
47340
47682
  }
47341
47683
  walk(path, "", root, 0);
47342
47684
  safe(path);
47343
47685
  return { path, sha256: hash.digest("hex") };
47344
47686
  }
47345
47687
  function captureDiscoveryDirectoryProjection(paths, omittedRoots) {
47346
- need(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid projected discovery directory collection");
47347
- need(omittedRoots.length <= AGENT_POLICY_LIMITS.discoveryRoots && new Set(omittedRoots).size === omittedRoots.length, "Invalid inactive discovery roots");
47688
+ need2(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid projected discovery directory collection");
47689
+ need2(omittedRoots.length <= AGENT_POLICY_LIMITS.discoveryRoots && new Set(omittedRoots).size === omittedRoots.length, "Invalid inactive discovery roots");
47348
47690
  for (const root of omittedRoots)
47349
47691
  safe(root);
47350
- const budget = { entries: 0, bytes: 0 };
47692
+ const budget2 = { entries: 0, bytes: 0 };
47351
47693
  return paths.map((path) => {
47352
47694
  const entries = [];
47353
- return { ...capture(path, budget, [], omittedRoots, entries), entries };
47695
+ return { ...capture(path, budget2, [], omittedRoots, entries), entries };
47354
47696
  });
47355
47697
  }
47356
47698
  function verifyDiscoveryDirectoryProjection(directories, omittedRoots) {
47357
- need(directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid projected discovery directory collection");
47699
+ need2(directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid projected discovery directory collection");
47358
47700
  let count = 0, bytes = 0;
47359
47701
  const expected = directories.map((directory) => {
47360
47702
  safe(directory.path);
47361
- need(Array.isArray(directory.entries), "Missing reviewed directory membership inventory");
47362
- const hash = createHash2("sha256");
47703
+ need2(Array.isArray(directory.entries), "Missing reviewed directory membership inventory");
47704
+ const hash = createHash4("sha256");
47363
47705
  const kept = [];
47364
47706
  for (const row of directory.entries) {
47365
- need(typeof row === "string" && ++count <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Invalid reviewed directory membership rows");
47707
+ need2(typeof row === "string" && ++count <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Invalid reviewed directory membership rows");
47366
47708
  bytes += Buffer.byteLength(row);
47367
- need(bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Reviewed directory membership byte limit exceeded");
47709
+ need2(bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Reviewed directory membership byte limit exceeded");
47368
47710
  const value = JSON.parse(row);
47369
- need(Array.isArray(value) && value.length === 2 && typeof value[0] === "string" && value[0] && !isAbsolute4(value[0]) && !value[0].split("/").some((part) => !part || part === "." || part === "..") && ["file", "directory"].includes(value[1]) && row === JSON.stringify(value) + `
47711
+ need2(Array.isArray(value) && value.length === 2 && typeof value[0] === "string" && value[0] && !isAbsolute5(value[0]) && !value[0].split("/").some((part) => !part || part === "." || part === "..") && ["file", "directory"].includes(value[1]) && row === JSON.stringify(value) + `
47370
47712
  `, "Invalid reviewed directory member");
47371
47713
  hash.update(row);
47372
47714
  const path = join12(directory.path, value[0]);
47373
47715
  if (!omittedRoots.some((root) => path === root || path.startsWith(root + "/")))
47374
47716
  kept.push(row);
47375
47717
  }
47376
- need(directory.sha256 === null ? directory.entries.length === 0 : hash.digest("hex") === directory.sha256, "Reviewed directory inventory does not match its fingerprint");
47718
+ need2(directory.sha256 === null ? directory.entries.length === 0 : hash.digest("hex") === directory.sha256, "Reviewed directory inventory does not match its fingerprint");
47377
47719
  const absent = omittedRoots.some((root) => directory.path === root || directory.path.startsWith(root + "/"));
47378
- return { path: directory.path, sha256: absent || directory.sha256 === null ? null : createHash2("sha256").update(kept.join("")).digest("hex") };
47720
+ return { path: directory.path, sha256: absent || directory.sha256 === null ? null : createHash4("sha256").update(kept.join("")).digest("hex") };
47379
47721
  });
47380
47722
  const current = captureDiscoveryDirectoryProjection(directories.map((item) => item.path), omittedRoots);
47381
- need(current.every((item, index) => item.sha256 === expected[index].sha256), "Native discovery directory membership changed outside retired Codex roots");
47723
+ need2(current.every((item, index) => item.sha256 === expected[index].sha256), "Native discovery directory membership changed outside retired Codex roots");
47382
47724
  }
47383
47725
  function captureDiscoveryDirectories(paths, excludedRoots = []) {
47384
- need(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
47385
- const budget = { entries: 0, bytes: 0 };
47726
+ need2(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
47727
+ const budget2 = { entries: 0, bytes: 0 };
47386
47728
  for (const root of excludedRoots)
47387
47729
  safe(root);
47388
- return paths.map((path) => capture(path, budget, excludedRoots));
47730
+ return paths.map((path) => capture(path, budget2, excludedRoots));
47389
47731
  }
47390
47732
  function verifyDiscoveryDirectories(directories, excludedRoots = []) {
47391
- need(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
47733
+ need2(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
47392
47734
  for (const directory of directories)
47393
- need(directory && typeof directory === "object" && (directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256)), "Invalid native discovery directory digest");
47735
+ need2(directory && typeof directory === "object" && (directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256)), "Invalid native discovery directory digest");
47394
47736
  const current = captureDiscoveryDirectories(directories.map((directory) => directory.path), excludedRoots);
47395
47737
  for (let i = 0;i < directories.length; i++)
47396
- need(current[i].sha256 === directories[i].sha256, `Native discovery directory membership changed; run skills hook install with a fresh discovery review: ${directories[i].path}`);
47738
+ need2(current[i].sha256 === directories[i].sha256, `Native discovery directory membership changed; run skills hook install with a fresh discovery review: ${directories[i].path}`);
47397
47739
  }
47398
47740
  var init_agent_discovery_directories = __esm(() => {
47399
47741
  init_agent_policy_limits();
47400
47742
  });
47401
47743
 
47402
47744
  // src/lib/agent-discovery-bytes.ts
47403
- import { createHash as createHash3 } from "crypto";
47404
- import { closeSync, constants as constants2, fstatSync, lstatSync as lstatSync5, openSync, readSync } from "fs";
47405
- import { dirname as dirname5, isAbsolute as isAbsolute5, resolve as resolve6 } from "path";
47745
+ import { createHash as createHash5 } from "crypto";
47746
+ import { closeSync as closeSync2, constants as constants3, fstatSync as fstatSync2, lstatSync as lstatSync6, openSync as openSync2, readSync as readSync2 } from "fs";
47747
+ import { dirname as dirname6, isAbsolute as isAbsolute6, resolve as resolve7 } from "path";
47406
47748
  function discoveryByteBudget() {
47407
47749
  return { remaining: AGENT_POLICY_LIMITS.discoveryRawTotalBytes };
47408
47750
  }
47409
47751
  function safe2(path) {
47410
- if (typeof path !== "string" || !isAbsolute5(path) || path !== resolve6(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00"))
47752
+ if (typeof path !== "string" || !isAbsolute6(path) || path !== resolve7(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00"))
47411
47753
  throw new Error("Expected a canonical absolute raw discovery path");
47412
- for (let cursor = path;; cursor = dirname5(cursor)) {
47413
- if (lstatSync5(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
47754
+ for (let cursor = path;; cursor = dirname6(cursor)) {
47755
+ if (lstatSync6(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
47414
47756
  throw new Error("Refusing symlink raw discovery input");
47415
- if (dirname5(cursor) === cursor)
47757
+ if (dirname6(cursor) === cursor)
47416
47758
  break;
47417
47759
  }
47418
47760
  }
47419
47761
  function same2(left, right) {
47420
47762
  return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs;
47421
47763
  }
47422
- function consume(budget, bytes) {
47423
- if (bytes > budget.remaining)
47764
+ function consume(budget2, bytes) {
47765
+ if (bytes > budget2.remaining)
47424
47766
  throw new Error("Raw discovery aggregate byte limit exceeded");
47425
- budget.remaining -= bytes;
47767
+ budget2.remaining -= bytes;
47426
47768
  }
47427
- function hashRawDiscoveryFile(path, budget, changes) {
47769
+ function hashRawDiscoveryFile(path, budget2, changes) {
47428
47770
  safe2(path);
47429
47771
  if (changes?.has(path)) {
47430
47772
  const text2 = changes.get(path), bytes = Buffer.byteLength(text2);
47431
47773
  if (bytes > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
47432
47774
  throw new Error("Raw discovery file byte limit exceeded");
47433
- consume(budget, bytes);
47434
- return createHash3("sha256").update(text2).digest("hex");
47775
+ consume(budget2, bytes);
47776
+ return createHash5("sha256").update(text2).digest("hex");
47435
47777
  }
47436
- const initial2 = lstatSync5(path, { throwIfNoEntry: false });
47778
+ const initial2 = lstatSync6(path, { throwIfNoEntry: false });
47437
47779
  if (!initial2)
47438
47780
  return null;
47439
47781
  if (!initial2.isFile() || initial2.size > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
47440
47782
  throw new Error("Unsupported or oversized raw discovery input");
47441
- if (initial2.size > budget.remaining)
47783
+ if (initial2.size > budget2.remaining)
47442
47784
  throw new Error("Raw discovery aggregate byte limit exceeded");
47443
- const fd = openSync(path, constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK);
47785
+ const fd = openSync2(path, constants3.O_RDONLY | constants3.O_NOFOLLOW | constants3.O_NONBLOCK);
47444
47786
  try {
47445
- const opened = fstatSync(fd);
47787
+ const opened = fstatSync2(fd);
47446
47788
  if (!opened.isFile() || !same2(initial2, opened))
47447
47789
  throw new Error("Raw discovery input changed during open");
47448
- const hash = createHash3("sha256"), buffer = Buffer.alloc(64 * 1024);
47790
+ const hash = createHash5("sha256"), buffer = Buffer.alloc(64 * 1024);
47449
47791
  let bytes = 0;
47450
47792
  while (true) {
47451
- const count = readSync(fd, buffer, 0, Math.min(buffer.length, AGENT_POLICY_LIMITS.discoveryRawSourceBytes - bytes + 1), null);
47793
+ const count = readSync2(fd, buffer, 0, Math.min(buffer.length, AGENT_POLICY_LIMITS.discoveryRawSourceBytes - bytes + 1), null);
47452
47794
  if (!count)
47453
47795
  break;
47454
47796
  bytes += count;
47455
47797
  if (bytes > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
47456
47798
  throw new Error("Raw discovery file byte limit exceeded");
47457
- consume(budget, count);
47799
+ consume(budget2, count);
47458
47800
  hash.update(buffer.subarray(0, count));
47459
47801
  }
47460
- const final = fstatSync(fd), current = lstatSync5(path, { throwIfNoEntry: false });
47802
+ const final = fstatSync2(fd), current = lstatSync6(path, { throwIfNoEntry: false });
47461
47803
  safe2(path);
47462
47804
  if (!current?.isFile() || !same2(opened, final) || !same2(final, current) || bytes !== final.size)
47463
47805
  throw new Error("Raw discovery input changed during read");
47464
47806
  return hash.digest("hex");
47465
47807
  } finally {
47466
- closeSync(fd);
47808
+ closeSync2(fd);
47467
47809
  }
47468
47810
  }
47469
47811
  var init_agent_discovery_bytes = __esm(() => {
@@ -47471,9 +47813,9 @@ var init_agent_discovery_bytes = __esm(() => {
47471
47813
  });
47472
47814
 
47473
47815
  // src/lib/agent-discovery-path-bytes.ts
47474
- import { createHash as createHash4 } from "crypto";
47475
- import { lstatSync as lstatSync6, readlinkSync } from "fs";
47476
- import { dirname as dirname6, isAbsolute as isAbsolute6, join as join13, parse, resolve as resolve7, sep as sep2 } from "path";
47816
+ import { createHash as createHash6 } from "crypto";
47817
+ import { lstatSync as lstatSync7, readlinkSync } from "fs";
47818
+ import { dirname as dirname7, isAbsolute as isAbsolute7, join as join13, parse as parse2, resolve as resolve8, sep as sep2 } from "path";
47477
47819
  function identity3(stat, mutable = false) {
47478
47820
  return {
47479
47821
  dev: String(stat.dev),
@@ -47484,14 +47826,14 @@ function identity3(stat, mutable = false) {
47484
47826
  ...mutable ? { size: String(stat.size), mtimeNs: String(stat.mtimeNs), ctimeNs: String(stat.ctimeNs) } : {}
47485
47827
  };
47486
47828
  }
47487
- function canonical(path) {
47488
- if (typeof path !== "string" || !isAbsolute6(path) || path !== resolve7(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00") || Buffer.from(path).toString("utf8") !== path)
47829
+ function canonical2(path) {
47830
+ if (typeof path !== "string" || !isAbsolute7(path) || path !== resolve8(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00") || Buffer.from(path).toString("utf8") !== path)
47489
47831
  throw new Error("Expected a canonical absolute discovery path");
47490
47832
  }
47491
47833
  function trace(path) {
47492
- canonical(path);
47834
+ canonical2(path);
47493
47835
  const rows = [], paths = [];
47494
- let metadataBytes = 0, steps = 0, links = 0, cursor = parse(path).root, pending = path.slice(cursor.length).split(sep2);
47836
+ let metadataBytes = 0, steps = 0, links = 0, cursor = parse2(path).root, pending = path.slice(cursor.length).split(sep2);
47495
47837
  function record2(path2, row) {
47496
47838
  const value = { path: path2, ...row };
47497
47839
  metadataBytes += Buffer.byteLength(JSON.stringify(value));
@@ -47501,7 +47843,7 @@ function trace(path) {
47501
47843
  paths.push(path2);
47502
47844
  }
47503
47845
  function root() {
47504
- const stat = lstatSync6(cursor, { bigint: true });
47846
+ const stat = lstatSync7(cursor, { bigint: true });
47505
47847
  if (!stat.isDirectory())
47506
47848
  throw new Error("Unsupported discovery path root");
47507
47849
  record2(cursor, { type: "directory", ...identity3(stat) });
@@ -47514,13 +47856,13 @@ function trace(path) {
47514
47856
  if (!component || component === ".")
47515
47857
  continue;
47516
47858
  if (component === "..") {
47517
- cursor = dirname6(cursor);
47859
+ cursor = dirname7(cursor);
47518
47860
  continue;
47519
47861
  }
47520
47862
  const candidate = join13(cursor, component);
47521
47863
  if (candidate.length > AGENT_POLICY_LIMITS.pathCharacters)
47522
47864
  throw new Error("Discovery resolved path length limit exceeded");
47523
- const stat = lstatSync6(candidate, { bigint: true, throwIfNoEntry: false });
47865
+ const stat = lstatSync7(candidate, { bigint: true, throwIfNoEntry: false });
47524
47866
  if (!stat) {
47525
47867
  record2(candidate, { type: "missing", remaining: pending });
47526
47868
  return { rows, paths, file: null, missing: candidate, metadataBytes };
@@ -47528,17 +47870,17 @@ function trace(path) {
47528
47870
  if (stat.isSymbolicLink()) {
47529
47871
  if (++links > AGENT_POLICY_LIMITS.discoveryPathLinks || stat.size > BigInt(AGENT_POLICY_LIMITS.pathCharacters))
47530
47872
  throw new Error("Discovery path link limit exceeded");
47531
- const rawTarget = readlinkSync(candidate, { encoding: "buffer" }), target = rawTarget.toString("utf8"), after2 = lstatSync6(candidate, { bigint: true });
47873
+ const rawTarget = readlinkSync(candidate, { encoding: "buffer" }), target = rawTarget.toString("utf8"), after2 = lstatSync7(candidate, { bigint: true });
47532
47874
  if (!rawTarget.equals(Buffer.from(target, "utf8")))
47533
47875
  throw new Error("Unsupported non-UTF8 discovery link target");
47534
47876
  if (!target || target.includes("\x00") || Buffer.byteLength(target) > AGENT_POLICY_LIMITS.pathCharacters || !after2.isSymbolicLink() || JSON.stringify(identity3(stat, true)) !== JSON.stringify(identity3(after2, true)))
47535
47877
  throw new Error("Discovery link changed during read");
47536
47878
  record2(candidate, { type: "link", target, ...identity3(stat, true) });
47537
- if (isAbsolute6(target)) {
47538
- cursor = parse(target).root;
47879
+ if (isAbsolute7(target)) {
47880
+ cursor = parse2(target).root;
47539
47881
  root();
47540
47882
  }
47541
- const remainder = isAbsolute6(target) ? target.slice(parse(target).root.length) : target;
47883
+ const remainder = isAbsolute7(target) ? target.slice(parse2(target).root.length) : target;
47542
47884
  pending = [...remainder.split(sep2), ...pending];
47543
47885
  if (pending.length + steps > AGENT_POLICY_LIMITS.discoveryPathSteps)
47544
47886
  throw new Error("Discovery path step limit exceeded");
@@ -47558,7 +47900,7 @@ function trace(path) {
47558
47900
  }
47559
47901
  throw new Error("Unsupported directory discovery path input");
47560
47902
  }
47561
- function hashDiscoveryPathFile(path, budget, changes) {
47903
+ function hashDiscoveryPathFile(path, budget2, changes) {
47562
47904
  const before2 = trace(path);
47563
47905
  let createsMissingPath = false;
47564
47906
  if (before2.missing !== null && changes) {
@@ -47571,17 +47913,17 @@ function hashDiscoveryPathFile(path, budget, changes) {
47571
47913
  }
47572
47914
  if (createsMissingPath || changes?.has(path) || before2.paths.some((path2) => changes?.has(path2)))
47573
47915
  throw new Error("Discovery path witness intersects a planned write; use bytes mode for owned configuration");
47574
- const remaining = budget.pathMetadataRemaining ?? AGENT_POLICY_LIMITS.discoveryPathTotalMetadataBytes;
47916
+ const remaining = budget2.pathMetadataRemaining ?? AGENT_POLICY_LIMITS.discoveryPathTotalMetadataBytes;
47575
47917
  if (before2.metadataBytes > remaining)
47576
47918
  throw new Error("Discovery path aggregate metadata limit exceeded");
47577
- budget.pathMetadataRemaining = remaining - before2.metadataBytes;
47578
- const content = before2.file === null ? null : hashRawDiscoveryFile(before2.file, budget);
47919
+ budget2.pathMetadataRemaining = remaining - before2.metadataBytes;
47920
+ const content = before2.file === null ? null : hashRawDiscoveryFile(before2.file, budget2);
47579
47921
  if (before2.file !== null && content === null)
47580
47922
  throw new Error("Discovery path input changed during read");
47581
47923
  const after2 = trace(path);
47582
47924
  if (JSON.stringify(before2.rows) !== JSON.stringify(after2.rows) || before2.file !== after2.file)
47583
47925
  throw new Error("Discovery path input changed during read");
47584
- return createHash4("sha256").update(JSON.stringify({ version: 1, path, rows: before2.rows, content })).digest("hex");
47926
+ return createHash6("sha256").update(JSON.stringify({ version: 1, path, rows: before2.rows, content })).digest("hex");
47585
47927
  }
47586
47928
  var init_agent_discovery_path_bytes = __esm(() => {
47587
47929
  init_agent_policy_limits();
@@ -47589,7 +47931,7 @@ var init_agent_discovery_path_bytes = __esm(() => {
47589
47931
  });
47590
47932
 
47591
47933
  // src/lib/skill-bundle.ts
47592
- import { createHash as createHash5 } from "crypto";
47934
+ import { createHash as createHash7 } from "crypto";
47593
47935
  import { readFileSync as readFileSync8, readdirSync as readdirSync4, statSync as statSync5 } from "fs";
47594
47936
  import { join as join14, relative as relative2 } from "path";
47595
47937
  import { createGunzip } from "zlib";
@@ -47621,7 +47963,7 @@ function ownBytes(view) {
47621
47963
  return out;
47622
47964
  }
47623
47965
  function sha256Hex(bytes) {
47624
- return createHash5("sha256").update(bytes).digest("hex");
47966
+ return createHash7("sha256").update(bytes).digest("hex");
47625
47967
  }
47626
47968
  function collectSkillBundleEntries(dir) {
47627
47969
  const entries = [];
@@ -47850,7 +48192,7 @@ async function inspectSkillBundle(bundle, options = {}) {
47850
48192
  parser2.push(chunk2);
47851
48193
  bytesSinceYield += chunk2.byteLength;
47852
48194
  if (bytesSinceYield >= 256 * 1024) {
47853
- await new Promise((resolve8) => setTimeout(resolve8, 0));
48195
+ await new Promise((resolve9) => setTimeout(resolve9, 0));
47854
48196
  bytesSinceYield = 0;
47855
48197
  check();
47856
48198
  }
@@ -48210,21 +48552,21 @@ var init_profile_limits = __esm(() => {
48210
48552
  });
48211
48553
 
48212
48554
  // src/lib/selection-cache.ts
48213
- import { createHash as createHash6, randomUUID as randomUUID3 } from "crypto";
48555
+ import { createHash as createHash8, randomUUID as randomUUID3 } from "crypto";
48214
48556
  import { spawnSync } from "child_process";
48215
- import { closeSync as closeSync2, constants as constants3, fstatSync as fstatSync2, fsyncSync, linkSync, lstatSync as lstatSync7, mkdirSync as mkdirSync3, openSync as openSync2, readFileSync as readFileSync9, readlinkSync as readlinkSync2, readSync as readSync2, renameSync, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
48557
+ import { closeSync as closeSync3, constants as constants4, fstatSync as fstatSync3, fsyncSync, linkSync, lstatSync as lstatSync8, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as readFileSync9, readlinkSync as readlinkSync2, readSync as readSync3, renameSync, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
48216
48558
  import { hostname } from "os";
48217
- import { dirname as dirname7, join as join15, parse as parse2, resolve as resolve8 } from "path";
48559
+ import { dirname as dirname8, join as join15, parse as parse3, resolve as resolve9 } from "path";
48218
48560
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
48219
48561
  function selectionCacheRoot(options = {}) {
48220
- return resolve8(options.cacheDir ?? join15(getDataDirReadOnly(), "selection-cache"));
48562
+ return resolve9(options.cacheDir ?? join15(getDataDirReadOnly(), "selection-cache"));
48221
48563
  }
48222
48564
  function selectionKey(selection) {
48223
48565
  validateSelection(selection);
48224
48566
  return hash([selection.authority, selection.workspaceId, selection.slug, selection.version, selection.bundleDigest]);
48225
48567
  }
48226
48568
  function hash(value) {
48227
- return createHash6("sha256").update(JSON.stringify(value)).digest("hex");
48569
+ return createHash8("sha256").update(JSON.stringify(value)).digest("hex");
48228
48570
  }
48229
48571
  function validateSelection(selection) {
48230
48572
  if (!selection || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(selection.slug) || !isValidSkillVersion(selection.version) || !/^sha256:[a-f0-9]{64}$/.test(selection.bundleDigest) || typeof selection.workspaceId !== "string" || !selection.workspaceId.trim() || typeof selection.profileRevision !== "string" || !selection.profileRevision.trim()) {
@@ -48264,14 +48606,14 @@ function selectionBundlePath(selection, options = {}) {
48264
48606
  return join15(selectionCacheRoot(options), "objects", hash(selection.authority), hash(selection.workspaceId), `${selection.bundleDigest.slice(7)}.tar.gz`);
48265
48607
  }
48266
48608
  function assertRegularPath(path, createParents = false) {
48267
- const absolute = resolve8(path);
48268
- const root = parse2(absolute).root;
48609
+ const absolute = resolve9(path);
48610
+ const root = parse3(absolute).root;
48269
48611
  let cursor = root;
48270
48612
  const segments = absolute.slice(root.length).split("/");
48271
48613
  for (let index = 0;index < segments.length; index++) {
48272
48614
  cursor = join15(cursor, segments[index]);
48273
48615
  try {
48274
- const stat = lstatSync7(cursor);
48616
+ const stat = lstatSync8(cursor);
48275
48617
  if (stat.isSymbolicLink() || index < segments.length - 1 && !stat.isDirectory()) {
48276
48618
  throw new SkillSelectionError("UNSAFE_CACHE_PATH", "Skills cache paths must not traverse symlinks or non-directories.");
48277
48619
  }
@@ -48287,20 +48629,20 @@ function readRegularFile(path, limit) {
48287
48629
  assertRegularPath(path);
48288
48630
  let fd;
48289
48631
  try {
48290
- fd = openSync2(path, constants3.O_RDONLY | constants3.O_NOFOLLOW | constants3.O_NONBLOCK);
48632
+ fd = openSync3(path, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
48291
48633
  } catch (error) {
48292
48634
  if (error.code === "ENOENT")
48293
48635
  return null;
48294
48636
  throw error;
48295
48637
  }
48296
48638
  try {
48297
- const stat = fstatSync2(fd);
48639
+ const stat = fstatSync3(fd);
48298
48640
  if (!stat.isFile() || stat.size > limit)
48299
48641
  throw new SkillSelectionError("INVALID_CACHE_FILE", "The Skills cache contains an invalid or oversized file.");
48300
48642
  const bytes = Buffer.alloc(stat.size + 1);
48301
48643
  let size2 = 0;
48302
48644
  while (size2 < bytes.length) {
48303
- const read2 = readSync2(fd, bytes, size2, bytes.length - size2, null);
48645
+ const read2 = readSync3(fd, bytes, size2, bytes.length - size2, null);
48304
48646
  if (!read2)
48305
48647
  break;
48306
48648
  size2 += read2;
@@ -48309,7 +48651,7 @@ function readRegularFile(path, limit) {
48309
48651
  throw new SkillSelectionError("INVALID_CACHE_FILE", "The Skills cache file grew during its bounded read.");
48310
48652
  return bytes.subarray(0, size2);
48311
48653
  } finally {
48312
- closeSync2(fd);
48654
+ closeSync3(fd);
48313
48655
  }
48314
48656
  }
48315
48657
  function writeSelectionJson(path, value) {
@@ -48321,19 +48663,19 @@ function writeSelectionJson(path, value) {
48321
48663
  }
48322
48664
  function atomicWrite(path, bytes, mode, durable = false) {
48323
48665
  assertRegularPath(path, true);
48324
- const temporary = join15(dirname7(path), `.selection-${randomUUID3()}.tmp`);
48666
+ const temporary = join15(dirname8(path), `.selection-${randomUUID3()}.tmp`);
48325
48667
  try {
48326
- const fd = openSync2(temporary, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, mode);
48668
+ const fd = openSync3(temporary, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, mode);
48327
48669
  try {
48328
48670
  writeFileSync3(fd, bytes);
48329
48671
  if (durable)
48330
48672
  fsyncSync(fd);
48331
48673
  } finally {
48332
- closeSync2(fd);
48674
+ closeSync3(fd);
48333
48675
  }
48334
48676
  renameSync(temporary, path);
48335
48677
  if (durable)
48336
- syncDirectory(dirname7(path));
48678
+ syncDirectory(dirname8(path));
48337
48679
  } finally {
48338
48680
  try {
48339
48681
  unlinkSync(temporary);
@@ -48443,7 +48785,7 @@ function assertFreshCachedProfile(receipt, options = {}) {
48443
48785
  }
48444
48786
  }
48445
48787
  function projectSelectionLockPath(projectDir) {
48446
- return join15(resolve8(projectDir), ".skills", SELECTION_LOCK_FILE);
48788
+ return join15(resolve9(projectDir), ".skills", SELECTION_LOCK_FILE);
48447
48789
  }
48448
48790
  function readProjectSelection(projectDir) {
48449
48791
  const receipt = readSelectionJson(projectSelectionLockPath(projectDir));
@@ -48557,14 +48899,14 @@ function localLockIdentity() {
48557
48899
  }
48558
48900
  function readSessionLock(sessionId, options) {
48559
48901
  const path = `${sessionReceiptPath(sessionId, options)}.write-lock`;
48560
- const before2 = lstatSync7(path, { throwIfNoEntry: false });
48902
+ const before2 = lstatSync8(path, { throwIfNoEntry: false });
48561
48903
  if (!before2)
48562
48904
  return null;
48563
48905
  if (!before2.isFile() || ![1, 2].includes(before2.nlink) || (before2.mode & 63) !== 0 || process.getuid && before2.uid !== process.getuid()) {
48564
48906
  throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock is not a private regular file; recovery requires review.");
48565
48907
  }
48566
48908
  const bytes = readRegularFile(path, SESSION_LOCK_MAX_BYTES);
48567
- const after2 = lstatSync7(path, { throwIfNoEntry: false });
48909
+ const after2 = lstatSync8(path, { throwIfNoEntry: false });
48568
48910
  if (!bytes || !after2?.isFile() || before2.dev !== after2.dev || before2.ino !== after2.ino || before2.mtimeMs !== after2.mtimeMs || before2.mode !== after2.mode || before2.uid !== after2.uid || before2.gid !== after2.gid || before2.nlink !== after2.nlink) {
48569
48911
  throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock changed during inspection; recovery requires review.");
48570
48912
  }
@@ -48581,7 +48923,7 @@ function readSessionLock(sessionId, options) {
48581
48923
  if (after2.nlink === 2) {
48582
48924
  stagingPath = `${path}.${marker.operationId}.prepared`;
48583
48925
  assertRegularPath(stagingPath);
48584
- const staged = lstatSync7(stagingPath, { throwIfNoEntry: false });
48926
+ const staged = lstatSync8(stagingPath, { throwIfNoEntry: false });
48585
48927
  if (marker.publication !== "hard-link-v1" || !staged?.isFile() || staged.dev !== after2.dev || staged.ino !== after2.ino || staged.nlink !== 2 || staged.mode !== after2.mode || staged.uid !== after2.uid || staged.gid !== after2.gid) {
48586
48928
  throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock has an unbound publication link; recovery requires review.");
48587
48929
  }
@@ -48592,33 +48934,33 @@ function publishSessionLock(path, marker) {
48592
48934
  const stagingPath = `${path}.${marker.operationId}.prepared`;
48593
48935
  const bytes = Buffer.from(`${JSON.stringify({ ...marker, publication: "hard-link-v1" })}
48594
48936
  `);
48595
- const fd = openSync2(stagingPath, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, 384);
48596
- const stat = fstatSync2(fd);
48937
+ const fd = openSync3(stagingPath, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, 384);
48938
+ const stat = fstatSync3(fd);
48597
48939
  let published = false, handedOff = false;
48598
48940
  try {
48599
48941
  writeFileSync3(fd, bytes);
48600
48942
  fsyncSync(fd);
48601
48943
  linkSync(stagingPath, path);
48602
48944
  published = true;
48603
- syncDirectory(dirname7(path));
48604
- const staged = lstatSync7(stagingPath);
48945
+ syncDirectory(dirname8(path));
48946
+ const staged = lstatSync8(stagingPath);
48605
48947
  if (!staged.isFile() || staged.dev !== stat.dev || staged.ino !== stat.ino) {
48606
48948
  throw new SkillSelectionError("SESSION_WRITE_LOCK_CHANGED", "The initialized lock staging inode changed before publication completed.");
48607
48949
  }
48608
48950
  unlinkSync(stagingPath);
48609
- syncDirectory(dirname7(path));
48951
+ syncDirectory(dirname8(path));
48610
48952
  handedOff = true;
48611
48953
  return { path, stagingPath, fd, dev: stat.dev, ino: stat.ino };
48612
48954
  } finally {
48613
48955
  if (!handedOff) {
48614
48956
  try {
48615
48957
  for (const target of [...published ? [path] : [], stagingPath]) {
48616
- const current = lstatSync7(target, { throwIfNoEntry: false });
48958
+ const current = lstatSync8(target, { throwIfNoEntry: false });
48617
48959
  if (current?.isFile() && current.dev === stat.dev && current.ino === stat.ino)
48618
48960
  unlinkSync(target);
48619
48961
  }
48620
48962
  } finally {
48621
- closeSync2(fd);
48963
+ closeSync3(fd);
48622
48964
  }
48623
48965
  }
48624
48966
  }
@@ -48667,25 +49009,25 @@ function archiveSessionLock(lock, receipt, explicitLocalHost) {
48667
49009
  const guardPath = `${lock.path}.recovery-guard`;
48668
49010
  let guardFd;
48669
49011
  try {
48670
- guardFd = openSync2(guardPath, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, 384);
49012
+ guardFd = openSync3(guardPath, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, 384);
48671
49013
  } catch (error) {
48672
49014
  if (error.code === "EEXIST")
48673
49015
  return null;
48674
49016
  throw error;
48675
49017
  }
48676
- const guardStat = fstatSync2(guardFd);
49018
+ const guardStat = fstatSync3(guardFd);
48677
49019
  try {
48678
49020
  writeFileSync3(guardFd, `${JSON.stringify({ schemaVersion: 1, pid: process.pid, operationId: randomUUID3() })}
48679
49021
  `);
48680
49022
  fsyncSync(guardFd);
48681
- const cacheOptions = { cacheDir: dirname7(dirname7(lock.path)) };
49023
+ const cacheOptions = { cacheDir: dirname8(dirname8(lock.path)) };
48682
49024
  const current = readSessionLock(lock.marker.sessionId, cacheOptions);
48683
49025
  if (!current || current.dev !== lock.dev || current.ino !== lock.ino || current.sha256 !== lock.sha256 || current.mtimeMs !== lock.mtimeMs || !writerIsGone(current, explicitLocalHost))
48684
49026
  return null;
48685
49027
  const currentReceipt = readSkillSessionSnapshotIfExists(lock.marker.sessionId, cacheOptions);
48686
49028
  if (currentReceipt?.sha256 !== receipt?.sha256 || currentReceipt?.generation !== receipt?.generation)
48687
49029
  return null;
48688
- const directory = join15(dirname7(dirname7(lock.path)), "session-lock-recoveries", randomUUID3());
49030
+ const directory = join15(dirname8(dirname8(lock.path)), "session-lock-recoveries", randomUUID3());
48689
49031
  const archivePath = join15(directory, "original.write-lock");
48690
49032
  const recordPath = join15(directory, "recovery.json");
48691
49033
  assertRegularPath(archivePath, true);
@@ -48702,7 +49044,7 @@ function archiveSessionLock(lock, receipt, explicitLocalHost) {
48702
49044
  })}
48703
49045
  `));
48704
49046
  syncDirectory(directory);
48705
- syncDirectory(dirname7(directory));
49047
+ syncDirectory(dirname8(directory));
48706
49048
  const finalLock = readSessionLock(lock.marker.sessionId, cacheOptions);
48707
49049
  if (!finalLock || finalLock.dev !== lock.dev || finalLock.ino !== lock.ino || finalLock.sha256 !== lock.sha256 || readSkillSessionSnapshotIfExists(lock.marker.sessionId, cacheOptions)?.sha256 !== receipt?.sha256)
48708
49050
  return null;
@@ -48717,11 +49059,11 @@ function archiveSessionLock(lock, receipt, explicitLocalHost) {
48717
49059
  archivedPaths.push(publicationPath);
48718
49060
  }
48719
49061
  syncDirectory(directory);
48720
- syncDirectory(dirname7(lock.path));
49062
+ syncDirectory(dirname8(lock.path));
48721
49063
  for (const path of archivedPaths) {
48722
- const before2 = lstatSync7(path, { throwIfNoEntry: false });
49064
+ const before2 = lstatSync8(path, { throwIfNoEntry: false });
48723
49065
  const bytes = readRegularFile(path, SESSION_LOCK_MAX_BYTES);
48724
- const after2 = lstatSync7(path, { throwIfNoEntry: false });
49066
+ const after2 = lstatSync8(path, { throwIfNoEntry: false });
48725
49067
  if (!before2?.isFile() || before2.dev !== lock.dev || before2.ino !== lock.ino || before2.nlink !== archivedPaths.length || before2.mtimeMs !== lock.mtimeMs || (before2.mode & 63) !== 0 || process.getuid && before2.uid !== process.getuid() || !bytes || sha256Hex(bytes) !== lock.sha256 || !after2?.isFile() || before2.dev !== after2.dev || before2.ino !== after2.ino || before2.mtimeMs !== after2.mtimeMs || before2.mode !== after2.mode || before2.uid !== after2.uid || before2.gid !== after2.gid || before2.nlink !== after2.nlink) {
48726
49068
  throw new Error("Archived lock ownership or bytes changed");
48727
49069
  }
@@ -48733,8 +49075,8 @@ function archiveSessionLock(lock, receipt, explicitLocalHost) {
48733
49075
  }
48734
49076
  return archivePath;
48735
49077
  } finally {
48736
- closeSync2(guardFd);
48737
- const current = lstatSync7(guardPath, { throwIfNoEntry: false });
49078
+ closeSync3(guardFd);
49079
+ const current = lstatSync8(guardPath, { throwIfNoEntry: false });
48738
49080
  if (current?.isFile() && current.dev === guardStat.dev && current.ino === guardStat.ino)
48739
49081
  unlinkSync(guardPath);
48740
49082
  }
@@ -48756,7 +49098,7 @@ function withSessionWriteLocks(sessionIds, options, action) {
48756
49098
  const owned = [];
48757
49099
  const assertOwned = () => {
48758
49100
  for (const lock of owned) {
48759
- const current = lstatSync7(lock.path, { throwIfNoEntry: false });
49101
+ const current = lstatSync8(lock.path, { throwIfNoEntry: false });
48760
49102
  if (!current?.isFile() || current.dev !== lock.dev || current.ino !== lock.ino) {
48761
49103
  throw new SkillSelectionError("SESSION_WRITE_LOCK_CHANGED", "A session write lock changed during the operation; no replacement is permitted.");
48762
49104
  }
@@ -48800,12 +49142,12 @@ function withSessionWriteLocks(sessionIds, options, action) {
48800
49142
  for (const lock of owned.reverse()) {
48801
49143
  try {
48802
49144
  for (const path of [lock.path, lock.stagingPath]) {
48803
- const current = lstatSync7(path, { throwIfNoEntry: false });
49145
+ const current = lstatSync8(path, { throwIfNoEntry: false });
48804
49146
  if (current?.isFile() && current.dev === lock.dev && current.ino === lock.ino)
48805
49147
  unlinkSync(path);
48806
49148
  }
48807
49149
  } finally {
48808
- closeSync2(lock.fd);
49150
+ closeSync3(lock.fd);
48809
49151
  }
48810
49152
  }
48811
49153
  }
@@ -48856,21 +49198,21 @@ function writeSkillSession(receipt, expected, options = {}) {
48856
49198
  }
48857
49199
  function syncDirectory(path) {
48858
49200
  assertRegularPath(path);
48859
- const fd = openSync2(path, constants3.O_RDONLY | constants3.O_DIRECTORY | constants3.O_NOFOLLOW);
49201
+ const fd = openSync3(path, constants4.O_RDONLY | constants4.O_DIRECTORY | constants4.O_NOFOLLOW);
48860
49202
  try {
48861
49203
  fsyncSync(fd);
48862
49204
  } finally {
48863
- closeSync2(fd);
49205
+ closeSync3(fd);
48864
49206
  }
48865
49207
  }
48866
49208
  function archiveBytes(path, bytes) {
48867
49209
  assertRegularPath(path, true);
48868
- const fd = openSync2(path, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, 384);
49210
+ const fd = openSync3(path, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, 384);
48869
49211
  try {
48870
49212
  writeFileSync3(fd, bytes);
48871
49213
  fsyncSync(fd);
48872
49214
  } finally {
48873
- closeSync2(fd);
49215
+ closeSync3(fd);
48874
49216
  }
48875
49217
  }
48876
49218
  function replaceSkillSession(expected, replacement, plan, options = {}, beforeCommit = () => {}) {
@@ -48897,7 +49239,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
48897
49239
  archiveBytes(receiptPath, Buffer.from(`${JSON.stringify(receipt)}
48898
49240
  `));
48899
49241
  syncDirectory(directory);
48900
- syncDirectory(dirname7(directory));
49242
+ syncDirectory(dirname8(directory));
48901
49243
  syncDirectory(selectionCacheRoot(options));
48902
49244
  if (sha256Hex(readRegularFile(archivePath, MAX_PROFILE_DOCUMENT_BYTES)) !== before2.sha256 || !sameSnapshot(readSkillSessionSnapshot(replacement.sessionId, options), expected)) {
48903
49245
  throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The session or its preservation archive changed before replacement; retained evidence must be reviewed.");
@@ -48937,12 +49279,12 @@ import { spawnSync as spawnSync2 } from "child_process";
48937
49279
  import { closeSync as closeSync22, fstatSync as fstatSync22, openSync as openSync22, readFileSync as readFileSync22 } from "fs";
48938
49280
  import { O_NOFOLLOW as O_NOFOLLOW2, O_NONBLOCK as O_NONBLOCK2, O_RDONLY as O_RDONLY2 } from "constants";
48939
49281
  import { hostname as osHostname } from "os";
48940
- import { isAbsolute as isAbsolute7, join as join22 } from "path";
49282
+ import { isAbsolute as isAbsolute8, join as join22 } from "path";
48941
49283
  import { createRequire } from "module";
48942
49284
  import { fileURLToPath as fileURLToPath2 } from "url";
48943
- import { closeSync as closeSync3, fstatSync as fstatSync3, lstatSync as lstatSync8, openSync as openSync3, readFileSync as readFileSync10, realpathSync as realpathSync2, statSync as statSync6 } from "fs";
49285
+ import { closeSync as closeSync4, fstatSync as fstatSync4, lstatSync as lstatSync9, openSync as openSync4, readFileSync as readFileSync10, realpathSync as realpathSync2, statSync as statSync6 } from "fs";
48944
49286
  import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
48945
- import { basename as basename3, dirname as dirname8, join as join16, relative as relative3, sep as sep3 } from "path";
49287
+ import { basename as basename4, dirname as dirname9, join as join16, relative as relative3, sep as sep3 } from "path";
48946
49288
  import { fileURLToPath, pathToFileURL } from "url";
48947
49289
  function envToken(name) {
48948
49290
  return name.toUpperCase().replace(/-/g, "_");
@@ -49017,15 +49359,15 @@ function o(e2, r2, t2) {
49017
49359
  }
49018
49360
  function entryPoint(directory) {
49019
49361
  const root = realpathSync2(directory);
49020
- const fd = openSync3(join16(root, "package.json"), O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
49362
+ const fd = openSync4(join16(root, "package.json"), O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
49021
49363
  let pkg;
49022
49364
  try {
49023
- const stat = fstatSync3(fd);
49365
+ const stat = fstatSync4(fd);
49024
49366
  if (!stat.isFile() || stat.size > MAX_PACKAGE_BYTES)
49025
49367
  throw new Error("Invalid Secrets package metadata");
49026
49368
  pkg = JSON.parse(readFileSync10(fd, "utf8"));
49027
49369
  } finally {
49028
- closeSync3(fd);
49370
+ closeSync4(fd);
49029
49371
  }
49030
49372
  if (!pkg || typeof pkg !== "object" || !("name" in pkg) || pkg.name !== PACKAGE) {
49031
49373
  throw new Error("Invalid Secrets package identity");
@@ -49045,13 +49387,13 @@ function entryPoint(directory) {
49045
49387
  return pathToFileURL(file).href;
49046
49388
  }
49047
49389
  function resolveInstalledSecrets(parentUrl) {
49048
- let directory = dirname8(fileURLToPath(parentUrl));
49390
+ let directory = dirname9(fileURLToPath(parentUrl));
49049
49391
  for (;; ) {
49050
- if (basename3(directory) !== "node_modules") {
49392
+ if (basename4(directory) !== "node_modules") {
49051
49393
  const candidate = join16(directory, "node_modules", PACKAGE);
49052
49394
  let absent = false;
49053
49395
  try {
49054
- lstatSync8(candidate);
49396
+ lstatSync9(candidate);
49055
49397
  } catch (error) {
49056
49398
  if (error.code !== "ENOENT")
49057
49399
  throw error;
@@ -49060,7 +49402,7 @@ function resolveInstalledSecrets(parentUrl) {
49060
49402
  if (!absent)
49061
49403
  return entryPoint(candidate);
49062
49404
  }
49063
- const parent = dirname8(directory);
49405
+ const parent = dirname9(directory);
49064
49406
  if (parent === directory)
49065
49407
  throw new Error("Secrets SDK is not installed for this consumer");
49066
49408
  directory = parent;
@@ -49072,7 +49414,7 @@ function homeDir(env3) {
49072
49414
  }
49073
49415
  function absoluteOverride(env3, key) {
49074
49416
  const value = env3[key]?.trim();
49075
- return value && isAbsolute7(value) ? value : null;
49417
+ return value && isAbsolute8(value) ? value : null;
49076
49418
  }
49077
49419
  function hasnaHomeDir(env3) {
49078
49420
  const override = absoluteOverride(env3, HASNA_HOME_ENV_KEY);
@@ -49768,7 +50110,7 @@ function selectedCliSkillsCredentialProfile() {
49768
50110
  var cliCredentialProfile;
49769
50111
 
49770
50112
  // src/lib/instance-credentials.ts
49771
- import { closeSync as closeSync4, constants as constants4, fstatSync as fstatSync4, lstatSync as lstatSync9, openSync as openSync4, readSync as readSync3 } from "fs";
50113
+ import { closeSync as closeSync5, constants as constants5, fstatSync as fstatSync5, lstatSync as lstatSync10, openSync as openSync5, readSync as readSync4 } from "fs";
49772
50114
  function selectedSkillsProfile(env3, explicit) {
49773
50115
  const selected = explicit ?? selectedCliSkillsCredentialProfile() ?? env3.HASNA_PROFILE;
49774
50116
  if (selected === undefined)
@@ -49783,7 +50125,7 @@ function skillsProfileCredentialFiles(env3, explicit) {
49783
50125
  }
49784
50126
  function fileIdentity(file) {
49785
50127
  try {
49786
- return lstatSync9(file);
50128
+ return lstatSync10(file);
49787
50129
  } catch (error) {
49788
50130
  if (["ENOENT", "ENOTDIR"].includes(error.code ?? ""))
49789
50131
  return null;
@@ -49804,14 +50146,14 @@ function captureSkillsCredentialFiles(files) {
49804
50146
  function readMetadataText(file) {
49805
50147
  let fd;
49806
50148
  try {
49807
- fd = openSync4(file, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
50149
+ fd = openSync5(file, constants5.O_RDONLY | constants5.O_NOFOLLOW | constants5.O_NONBLOCK);
49808
50150
  } catch (error) {
49809
50151
  if (["ENOENT", "ENOTDIR"].includes(error.code ?? ""))
49810
50152
  return null;
49811
50153
  throw new Error("Cannot safely read Skills instance configuration");
49812
50154
  }
49813
50155
  try {
49814
- const before2 = fstatSync4(fd);
50156
+ const before2 = fstatSync5(fd);
49815
50157
  const uid = process.getuid?.() ?? process.geteuid?.();
49816
50158
  if (!before2.isFile() || ![256, 384].includes(before2.mode & 4095) || uid !== undefined && before2.uid !== uid || before2.size > 64 * 1024) {
49817
50159
  throw new Error("Unsafe Skills instance configuration; expected a bounded owner-only regular file");
@@ -49819,17 +50161,17 @@ function readMetadataText(file) {
49819
50161
  const bytes = Buffer.alloc(64 * 1024 + 1);
49820
50162
  let length = 0;
49821
50163
  while (length < bytes.length) {
49822
- const count = readSync3(fd, bytes, length, bytes.length - length, null);
50164
+ const count = readSync4(fd, bytes, length, bytes.length - length, null);
49823
50165
  if (!count)
49824
50166
  break;
49825
50167
  length += count;
49826
50168
  }
49827
- if (length > 64 * 1024 || !unchanged(before2, fstatSync4(fd)) || !unchanged(before2, fileIdentity(file))) {
50169
+ if (length > 64 * 1024 || !unchanged(before2, fstatSync5(fd)) || !unchanged(before2, fileIdentity(file))) {
49828
50170
  throw new Error("Skills instance configuration changed while reading");
49829
50171
  }
49830
50172
  return bytes.subarray(0, length).toString("utf8");
49831
50173
  } finally {
49832
- closeSync4(fd);
50174
+ closeSync5(fd);
49833
50175
  }
49834
50176
  }
49835
50177
  function readSkillsInstanceMetadata(file) {
@@ -50336,7 +50678,7 @@ __export(exports_remote_files, {
50336
50678
  decodeRemoteFiles: () => decodeRemoteFiles,
50337
50679
  MAX_REMOTE_FILE_BYTES: () => MAX_REMOTE_FILE_BYTES
50338
50680
  });
50339
- import { createHash as createHash7 } from "crypto";
50681
+ import { createHash as createHash9 } from "crypto";
50340
50682
  function describeRemoteFiles(files) {
50341
50683
  if (files.length > 10)
50342
50684
  throw new Error("At most 10 input files are supported");
@@ -50353,7 +50695,7 @@ function describeRemoteFiles(files) {
50353
50695
  });
50354
50696
  }
50355
50697
  function sha256(bytes) {
50356
- return createHash7("sha256").update(bytes).digest("hex");
50698
+ return createHash9("sha256").update(bytes).digest("hex");
50357
50699
  }
50358
50700
  async function readBoundedResponse(response, maximum) {
50359
50701
  if (!Number.isSafeInteger(maximum) || maximum < 0 || maximum > MAX_REMOTE_FILE_BYTES)
@@ -50608,11 +50950,11 @@ function capturePreparationProcess(child, platform2 = process.platform, signalGr
50608
50950
  }
50609
50951
 
50610
50952
  // src/lib/dependency-preparation.ts
50611
- import { constants as constants5, closeSync as closeSync5, fstatSync as fstatSync5, lstatSync as lstatSync10, mkdirSync as mkdirSync4, openSync as openSync5, readFileSync as readFileSync11, readdirSync as readdirSync5, rmdirSync, unlinkSync as unlinkSync2, ftruncateSync, writeSync } from "fs";
50953
+ import { constants as constants6, closeSync as closeSync6, fstatSync as fstatSync6, lstatSync as lstatSync11, mkdirSync as mkdirSync4, openSync as openSync6, readFileSync as readFileSync11, readdirSync as readdirSync5, rmdirSync, unlinkSync as unlinkSync2, ftruncateSync, writeSync } from "fs";
50612
50954
  import { join as join17 } from "path";
50613
50955
  function hasDependencyPreparationMarker(skillPath) {
50614
50956
  try {
50615
- lstatSync10(join17(skillPath, DEPENDENCY_PREPARATION_MARKER));
50957
+ lstatSync11(join17(skillPath, DEPENDENCY_PREPARATION_MARKER));
50616
50958
  return true;
50617
50959
  } catch (error) {
50618
50960
  return error.code !== "ENOENT";
@@ -50631,21 +50973,21 @@ function claimPreparation(skillPath) {
50631
50973
  }
50632
50974
  let fd;
50633
50975
  try {
50634
- if (!lstatSync10(marker).isDirectory() || lstatSync10(marker).isSymbolicLink())
50976
+ if (!lstatSync11(marker).isDirectory() || lstatSync11(marker).isSymbolicLink())
50635
50977
  return;
50636
50978
  if (!created) {
50637
50979
  if (readdirSync5(marker).some((name) => name !== "state.json"))
50638
50980
  return;
50639
- if (!lstatSync10(state).isFile() || lstatSync10(state).isSymbolicLink() || lstatSync10(state).size > 1024)
50981
+ if (!lstatSync11(state).isFile() || lstatSync11(state).isSymbolicLink() || lstatSync11(state).size > 1024)
50640
50982
  return;
50641
50983
  const previous = JSON.parse(readFileSync11(state, "utf8"));
50642
50984
  if (previous.version !== 1 || previous.status !== "failed" || Object.keys(previous).length !== 2)
50643
50985
  return;
50644
50986
  }
50645
50987
  mkdirSync4(active, { mode: 448 });
50646
- fd = openSync5(state, constants5.O_RDWR | constants5.O_NOFOLLOW | (created ? constants5.O_CREAT | constants5.O_EXCL : 0), 384);
50647
- if (!fstatSync5(fd).isFile()) {
50648
- closeSync5(fd);
50988
+ fd = openSync6(state, constants6.O_RDWR | constants6.O_NOFOLLOW | (created ? constants6.O_CREAT | constants6.O_EXCL : 0), 384);
50989
+ if (!fstatSync6(fd).isFile()) {
50990
+ closeSync6(fd);
50649
50991
  return;
50650
50992
  }
50651
50993
  const descriptor = fd;
@@ -50657,7 +50999,7 @@ function claimPreparation(skillPath) {
50657
50999
  record2("pending");
50658
51000
  return { abandon() {
50659
51001
  try {
50660
- closeSync5(descriptor);
51002
+ closeSync6(descriptor);
50661
51003
  } catch {}
50662
51004
  }, finish(success) {
50663
51005
  try {
@@ -50665,7 +51007,7 @@ function claimPreparation(skillPath) {
50665
51007
  unlinkSync2(state);
50666
51008
  else
50667
51009
  record2("failed");
50668
- closeSync5(descriptor);
51010
+ closeSync6(descriptor);
50669
51011
  fd = undefined;
50670
51012
  rmdirSync(active);
50671
51013
  if (success)
@@ -50673,7 +51015,7 @@ function claimPreparation(skillPath) {
50673
51015
  return true;
50674
51016
  } catch {
50675
51017
  try {
50676
- closeSync5(descriptor);
51018
+ closeSync6(descriptor);
50677
51019
  } catch {}
50678
51020
  return false;
50679
51021
  }
@@ -50681,7 +51023,7 @@ function claimPreparation(skillPath) {
50681
51023
  } catch {
50682
51024
  if (fd !== undefined)
50683
51025
  try {
50684
- closeSync5(fd);
51026
+ closeSync6(fd);
50685
51027
  } catch {}
50686
51028
  return;
50687
51029
  }
@@ -50774,32 +51116,32 @@ var init_dependency_preparation = () => {};
50774
51116
  // src/lib/codex-corpus-write.ts
50775
51117
  import { KernelLock } from "@hasna/contracts/kernel-lock";
50776
51118
  import { execFileSync } from "child_process";
50777
- import { createHash as createHash8 } from "crypto";
50778
- import { accessSync, constants as constants6, lstatSync as lstatSync11, readFileSync as readFileSync12, realpathSync as realpathSync3, statSync as statSync7 } from "fs";
50779
- import { basename as basename4, delimiter, dirname as dirname9, isAbsolute as isAbsolute8, join as join18, relative as relative4, resolve as resolve9, sep as sep4 } from "path";
51119
+ import { createHash as createHash10 } from "crypto";
51120
+ import { accessSync, constants as constants7, lstatSync as lstatSync12, readFileSync as readFileSync12, realpathSync as realpathSync3, statSync as statSync7 } from "fs";
51121
+ import { basename as basename5, delimiter, dirname as dirname10, isAbsolute as isAbsolute9, join as join18, relative as relative4, resolve as resolve10, sep as sep4 } from "path";
50780
51122
  function physicalTarget(path) {
50781
51123
  const suffix = [];
50782
- for (let cursor = path;; cursor = dirname9(cursor)) {
51124
+ for (let cursor = path;; cursor = dirname10(cursor)) {
50783
51125
  try {
50784
51126
  return join18(realpathSync3(cursor), ...suffix);
50785
51127
  } catch (error) {
50786
- if (error.code !== "ENOENT" || cursor === dirname9(cursor))
51128
+ if (error.code !== "ENOENT" || cursor === dirname10(cursor))
50787
51129
  throw error;
50788
51130
  try {
50789
- if (lstatSync11(cursor).isSymbolicLink())
51131
+ if (lstatSync12(cursor).isSymbolicLink())
50790
51132
  fail2();
50791
51133
  } catch (statError) {
50792
51134
  if (statError.code !== "ENOENT")
50793
51135
  throw statError;
50794
51136
  }
50795
- suffix.unshift(basename4(cursor));
51137
+ suffix.unshift(basename5(cursor));
50796
51138
  }
50797
51139
  }
50798
51140
  }
50799
51141
  function codexCorpusRootForPath(path) {
50800
- const target = resolve9(path), physical = physicalTarget(target);
51142
+ const target = resolve10(path), physical = physicalTarget(target);
50801
51143
  const selected = process.env.CODEX_HOME;
50802
- const selectedRoots = selected && isAbsolute8(selected) ? [resolve9(selected), physicalTarget(resolve9(selected))] : [];
51144
+ const selectedRoots = selected && isAbsolute9(selected) ? [resolve10(selected), physicalTarget(resolve10(selected))] : [];
50803
51145
  const classify = (candidate) => {
50804
51146
  const checked = (root2) => {
50805
51147
  if (candidate === root2 || candidate === join18(root2, `${KEY}.flock-v1`))
@@ -50808,10 +51150,10 @@ function codexCorpusRootForPath(path) {
50808
51150
  };
50809
51151
  for (const root2 of selectedRoots) {
50810
51152
  const distance = relative4(root2, candidate);
50811
- if (distance === "" || !distance.startsWith(`..${sep4}`) && distance !== ".." && !isAbsolute8(distance))
51153
+ if (distance === "" || !distance.startsWith(`..${sep4}`) && distance !== ".." && !isAbsolute9(distance))
50812
51154
  return checked(root2);
50813
51155
  }
50814
- for (let cursor = candidate;cursor !== dirname9(cursor); cursor = dirname9(cursor)) {
51156
+ for (let cursor = candidate;cursor !== dirname10(cursor); cursor = dirname10(cursor)) {
50815
51157
  if (cursor.endsWith(`${sep4}.codex`))
50816
51158
  return checked(cursor);
50817
51159
  }
@@ -50823,7 +51165,7 @@ function codexCorpusRootForPath(path) {
50823
51165
  return root;
50824
51166
  }
50825
51167
  function identity4(path) {
50826
- const stat = lstatSync11(path, { bigint: true });
51168
+ const stat = lstatSync12(path, { bigint: true });
50827
51169
  return { device: String(stat.dev), inode: String(stat.ino) };
50828
51170
  }
50829
51171
  function sameIdentity(value, expected) {
@@ -50837,12 +51179,12 @@ function executable(options) {
50837
51179
  if (typeof command !== "string" || !command || command.includes("\x00") || options.codexSha256 !== undefined && !/^[a-f0-9]{64}$/.test(options.codexSha256))
50838
51180
  return fail2();
50839
51181
  let found;
50840
- if (isAbsolute8(command))
51182
+ if (isAbsolute9(command))
50841
51183
  found = command;
50842
51184
  else if (!command.includes(sep4)) {
50843
- found = (process.env.PATH ?? "").split(delimiter).filter(isAbsolute8).map((dir) => join18(dir, command)).find((candidate) => {
51185
+ found = (process.env.PATH ?? "").split(delimiter).filter(isAbsolute9).map((dir) => join18(dir, command)).find((candidate) => {
50844
51186
  try {
50845
- accessSync(candidate, constants6.X_OK);
51187
+ accessSync(candidate, constants7.X_OK);
50846
51188
  return true;
50847
51189
  } catch {
50848
51190
  return false;
@@ -50854,7 +51196,7 @@ function executable(options) {
50854
51196
  const path = realpathSync3(found), initial2 = statSync7(path, { bigint: true });
50855
51197
  if (!initial2.isFile() || (initial2.mode & 0o022n) !== 0n || (initial2.mode & 0o111n) === 0n || initial2.uid !== BigInt(process.getuid()) && initial2.uid !== 0n)
50856
51198
  return fail2();
50857
- const hash2 = () => createHash8("sha256").update(readFileSync12(path)).digest("hex");
51199
+ const hash2 = () => createHash10("sha256").update(readFileSync12(path)).digest("hex");
50858
51200
  const digest = hash2();
50859
51201
  if (options.codexSha256 && digest !== options.codexSha256)
50860
51202
  return fail2();
@@ -50878,7 +51220,7 @@ function acquireCodexCorpusWrite(roots, options) {
50878
51220
  }
50879
51221
  };
50880
51222
  try {
50881
- if (roots.some((root) => typeof root !== "string" || !isAbsolute8(root) || root.includes("\x00")))
51223
+ if (roots.some((root) => typeof root !== "string" || !isAbsolute9(root) || root.includes("\x00")))
50882
51224
  fail2();
50883
51225
  const inputs = [...new Set(roots)].map((input) => ({ input, root: realpathSync3(input) })).sort((a, b) => a.root.localeCompare(b.root));
50884
51226
  for (const { input, root } of inputs) {
@@ -51011,293 +51353,6 @@ function isCodexLocalStdioMcpServer(name, server) {
51011
51353
  }
51012
51354
  }
51013
51355
 
51014
- // src/lib/claude-settings-witness.ts
51015
- import { createHash as createHash9 } from "crypto";
51016
- import { closeSync as closeSync6, constants as constants7, fstatSync as fstatSync6, lstatSync as lstatSync12, openSync as openSync6, readSync as readSync4 } from "fs";
51017
- import { basename as basename5, dirname as dirname10, isAbsolute as isAbsolute9, resolve as resolve10 } from "path";
51018
- function need2(value, reason) {
51019
- if (!value)
51020
- throw new Error(`Claude settings witness ${reason}`);
51021
- }
51022
- function absolutePath(value) {
51023
- need2(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute9(value) && resolve10(value) === value, "requires a normalized absolute path");
51024
- }
51025
- function parents(path) {
51026
- const result2 = [];
51027
- for (let at2 = dirname10(path);; at2 = dirname10(at2)) {
51028
- const stat = lstatSync12(at2, { bigint: true });
51029
- need2(stat.isDirectory() && !stat.isSymbolicLink(), "path traverses a symlink or non-directory");
51030
- result2.push([at2, stat]);
51031
- if (at2 === dirname10(at2))
51032
- return result2;
51033
- }
51034
- }
51035
- function readNativeSettingsWitnessFile(path, budget, filename = "settings.json") {
51036
- absolutePath(path);
51037
- need2(basename5(path) === filename, `requires ${filename}`);
51038
- need2(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
51039
- const ancestors = parents(path), initial2 = lstatSync12(path, { bigint: true });
51040
- need2(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_SETTINGS_WITNESS_LIMITS.bytes), "is not a bounded regular file");
51041
- need2(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
51042
- const fd = openSync6(path, constants7.O_RDONLY | constants7.O_NOFOLLOW | constants7.O_NONBLOCK);
51043
- try {
51044
- const opened = fstatSync6(fd, { bigint: true });
51045
- need2(opened.isFile() && sameFile(initial2, opened), "changed during open");
51046
- const bytes = Buffer.alloc(Number(opened.size) + 1);
51047
- let length = 0;
51048
- while (length < bytes.length) {
51049
- const count = readSync4(fd, bytes, length, bytes.length - length, null);
51050
- if (!count)
51051
- break;
51052
- length += count;
51053
- }
51054
- const after2 = fstatSync6(fd, { bigint: true }), current = lstatSync12(path, { bigint: true });
51055
- need2(current.isFile() && sameFile(opened, after2) && sameFile(after2, current) && BigInt(length) === opened.size, "changed during read");
51056
- for (const [ancestor, before2] of ancestors) {
51057
- const now3 = lstatSync12(ancestor, { bigint: true });
51058
- need2(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
51059
- }
51060
- budget.remaining -= length;
51061
- try {
51062
- return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
51063
- } catch {
51064
- throw new Error("Claude settings witness is not strict UTF-8");
51065
- }
51066
- } finally {
51067
- closeSync6(fd);
51068
- }
51069
- }
51070
- function parse3(text2) {
51071
- let at2 = 0, nodes = 0;
51072
- const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
51073
- const space = () => {
51074
- while (at2 < text2.length && /[\x20\t\r\n]/.test(text2[at2]))
51075
- at2++;
51076
- };
51077
- function string() {
51078
- need2(text2[at2] === '"', "contains invalid JSON");
51079
- const start = at2++;
51080
- while (at2 < text2.length) {
51081
- const character = text2[at2++];
51082
- if (character === '"') {
51083
- let value2;
51084
- try {
51085
- value2 = JSON.parse(text2.slice(start, at2));
51086
- } catch {
51087
- throw new Error("Claude settings witness contains invalid JSON string");
51088
- }
51089
- need2(value2.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.stringCharacters, "exceeds its string limit");
51090
- return value2;
51091
- }
51092
- if (character === "\\")
51093
- at2++;
51094
- }
51095
- throw new Error("Claude settings witness contains an unterminated JSON string");
51096
- }
51097
- function value(depth) {
51098
- need2(depth <= CLAUDE_SETTINGS_WITNESS_LIMITS.depth && ++nodes <= CLAUDE_SETTINGS_WITNESS_LIMITS.nodes, "exceeds its nesting or node limit");
51099
- space();
51100
- const character = text2[at2];
51101
- if (character === '"')
51102
- return { kind: "string", value: string() };
51103
- if (character === "{" || character === "[") {
51104
- at2++;
51105
- space();
51106
- const object4 = character === "{", end = object4 ? "}" : "]", entries = [], items = [], keys2 = new Set;
51107
- if (text2[at2] !== end)
51108
- while (true) {
51109
- if (object4) {
51110
- space();
51111
- const key = string();
51112
- need2(!keys2.has(key), "contains a duplicate JSON key");
51113
- keys2.add(key);
51114
- space();
51115
- need2(text2[at2++] === ":", "contains invalid JSON");
51116
- entries.push([key, value(depth + 1)]);
51117
- } else
51118
- items.push(value(depth + 1));
51119
- space();
51120
- if (text2[at2] === end)
51121
- break;
51122
- need2(text2[at2++] === ",", "contains invalid JSON");
51123
- }
51124
- at2++;
51125
- return object4 ? { kind: "object", entries } : { kind: "array", items };
51126
- }
51127
- for (const literal of ["true", "false", "null"])
51128
- if (text2.startsWith(literal, at2)) {
51129
- at2 += literal.length;
51130
- return { kind: "literal", value: literal };
51131
- }
51132
- numberPattern.lastIndex = at2;
51133
- const number = numberPattern.exec(text2);
51134
- need2(number, "contains invalid JSON");
51135
- at2 += number[0].length;
51136
- return { kind: "number", value: number[0] };
51137
- }
51138
- const root = value(0);
51139
- space();
51140
- need2(at2 === text2.length && root.kind === "object", "requires a JSON object without trailing content");
51141
- need2(root.entries.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.rows, "exceeds its settings field limit");
51142
- return root;
51143
- }
51144
- function canonical2(value) {
51145
- if (value.kind === "object")
51146
- return { kind: "object", entries: value.entries.map(([key, child]) => [key, canonical2(child)]).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0) };
51147
- if (value.kind === "array")
51148
- return { kind: "array", items: value.items.map(canonical2) };
51149
- return value;
51150
- }
51151
- function inferencePreference(key, child, version) {
51152
- if (key === "skipDangerousModePermissionPrompt") {
51153
- need2(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid dialog acknowledgment");
51154
- return false;
51155
- }
51156
- if (key === "effortLevel") {
51157
- need2(child.kind === "string" && PERSISTED_EFFORT_LEVELS.has(child.value), "contains an invalid persisted effort level");
51158
- return true;
51159
- }
51160
- if (key !== "modelSettings")
51161
- return false;
51162
- need2(child.kind === "object", "requires an object of model preferences");
51163
- child.entries = child.entries.filter(([model, preferences]) => {
51164
- if (version === 2 && !BUILTIN_MODEL_SELECTIONS.has(model) || preferences.kind !== "object" || preferences.entries.length !== 1 || preferences.entries[0][0] !== "effortLevel")
51165
- return true;
51166
- const effort = preferences.entries[0][1];
51167
- need2(effort.kind === "string" && PERSISTED_EFFORT_LEVELS.has(effort.value), "contains an invalid persisted model effort level");
51168
- return false;
51169
- });
51170
- return child.entries.length === 0;
51171
- }
51172
- function settingsDigest(text2, version = 1) {
51173
- const value = parse3(text2);
51174
- value.entries = value.entries.filter(([key, child]) => {
51175
- if (version !== 1 && inferencePreference(key, child, version))
51176
- return false;
51177
- if (key === "model") {
51178
- need2(child.kind === "string", "contains an invalid model selection");
51179
- return !BUILTIN_MODEL_SELECTIONS.has(child.value);
51180
- }
51181
- if (BOOLEAN_PREFERENCES.has(key)) {
51182
- need2(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid display preference");
51183
- return false;
51184
- }
51185
- if (Object.hasOwn(ENUM_PREFERENCES, key)) {
51186
- need2(child.kind === "string" && ENUM_PREFERENCES[key].includes(child.value), "contains an invalid display preference");
51187
- return false;
51188
- }
51189
- return true;
51190
- });
51191
- return createHash9("sha256").update(`hasna.skills.claude-settings.v${version}\x00`).update(JSON.stringify(canonical2(value))).digest("hex");
51192
- }
51193
- function hashClaudeSettingsReplacement(text2, budget) {
51194
- need2(typeof text2 === "string", "requires settings text");
51195
- const bytes = Buffer.byteLength(text2);
51196
- need2(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
51197
- budget.remaining -= bytes;
51198
- return settingsDigest(text2);
51199
- }
51200
- function captureClaudeSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
51201
- return { path, hashMode: "claude-settings-v1", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget)) };
51202
- }
51203
- function captureClaudeSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
51204
- return { path, hashMode: "claude-settings-v2", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 2) };
51205
- }
51206
- function hashClaudeSettingsReplacementV2(text2, budget) {
51207
- need2(typeof text2 === "string", "requires settings text");
51208
- const bytes = Buffer.byteLength(text2);
51209
- need2(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
51210
- budget.remaining -= bytes;
51211
- return settingsDigest(text2, 2);
51212
- }
51213
- function captureClaudeSettingsV3(path, budget = { remaining: 256 * 1024 * 1024 }) {
51214
- return { path, hashMode: "claude-settings-v3", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 3) };
51215
- }
51216
- function hashClaudeSettingsReplacementV3(text2, budget) {
51217
- need2(typeof text2 === "string", "requires settings text");
51218
- const bytes = Buffer.byteLength(text2);
51219
- need2(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
51220
- budget.remaining -= bytes;
51221
- return settingsDigest(text2, 3);
51222
- }
51223
- function upgradeClaudeSettingsWitness(previous, reviewedSettingsPath) {
51224
- need2(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes" || previous.hashMode === "claude-settings-v1" || previous.hashMode === "claude-settings-v2") && typeof previous.sha256 === "string" && /^[a-f0-9]{64}$/.test(previous.sha256), "requires an exact legacy settings witness");
51225
- const budget = { remaining: 2 * CLAUDE_SETTINGS_WITNESS_LIMITS.bytes };
51226
- const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget), current = readNativeSettingsWitnessFile(previous.path, budget);
51227
- const beforeDigest = previous.hashMode === undefined || previous.hashMode === "bytes" ? createHash9("sha256").update(before2).digest("hex") : settingsDigest(before2, previous.hashMode === "claude-settings-v1" ? 1 : 2);
51228
- need2(beforeDigest === previous.sha256, "reviewed preimage does not match the legacy witness");
51229
- const sha2562 = settingsDigest(current, 3);
51230
- need2(settingsDigest(before2, 3) === sha2562, "non-preference settings changed; explicit discovery review required");
51231
- return { path: previous.path, hashMode: "claude-settings-v3", sha256: sha2562 };
51232
- }
51233
- function hashNativeJsonControls(text2, excludedMetadata) {
51234
- need2(Buffer.byteLength(text2) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
51235
- const value = parse3(text2);
51236
- value.entries = value.entries.filter(([key, child]) => {
51237
- if (key !== excludedMetadata)
51238
- return true;
51239
- need2(child.kind === "string" && child.value.length <= 128, "has invalid version metadata");
51240
- return false;
51241
- });
51242
- return createHash9("sha256").update("hasna.skills.native-json-controls.v1\x00").update(JSON.stringify(canonical2(value))).digest("hex");
51243
- }
51244
- var CLAUDE_SETTINGS_WITNESS_LIMITS, sameFile = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, BOOLEAN_PREFERENCES, ENUM_PREFERENCES, BUILTIN_MODEL_SELECTIONS, PERSISTED_EFFORT_LEVELS;
51245
- var init_claude_settings_witness = __esm(() => {
51246
- CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
51247
- BOOLEAN_PREFERENCES = new Set([
51248
- "autoScrollEnabled",
51249
- "axScreenReader",
51250
- "emojiCompletionEnabled",
51251
- "prefersReducedMotion",
51252
- "showTurnDuration",
51253
- "spinnerTipsEnabled",
51254
- "syntaxHighlightingDisabled",
51255
- "terminalProgressBarEnabled",
51256
- "terminalTitleFromRename",
51257
- "verbose",
51258
- "wheelScrollAccelerationEnabled"
51259
- ]);
51260
- ENUM_PREFERENCES = Object.freeze({
51261
- editorMode: ["normal", "vim"],
51262
- tui: ["default", "fullscreen"],
51263
- viewMode: ["default", "verbose", "focus"]
51264
- });
51265
- BUILTIN_MODEL_SELECTIONS = new Set([
51266
- "default",
51267
- "best",
51268
- "fable",
51269
- "fable[1m]",
51270
- "sonnet",
51271
- "sonnet[1m]",
51272
- "opus",
51273
- "opus[1m]",
51274
- "haiku",
51275
- "opusplan",
51276
- "claude-fable-5-1",
51277
- "claude-fable-5",
51278
- "claude-fable-5[1m]",
51279
- "claude-opus-5",
51280
- "claude-sonnet-5",
51281
- "claude-haiku-4-5-20251001",
51282
- "claude-opus-4-6",
51283
- "claude-sonnet-4-5",
51284
- "claude-sonnet-4-5-20250929",
51285
- "claude-opus-4-8",
51286
- "claude-opus-4-8[1m]",
51287
- "claude-opus-4-7",
51288
- "claude-sonnet-4-6",
51289
- "claude-opus-4-5-20251101",
51290
- "claude-opus-4-5",
51291
- "claude-haiku-4-5",
51292
- "claude-fable-5-1[1m]",
51293
- "claude-opus-5[1m]",
51294
- "claude-opus-4-7[1m]",
51295
- "claude-opus-4-6[1m]",
51296
- "claude-sonnet-4-6[1m]"
51297
- ]);
51298
- PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
51299
- });
51300
-
51301
51356
  // src/lib/codex-native-compatibility.ts
51302
51357
  function supportsCodexNativeCapability(version, capability) {
51303
51358
  return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
@@ -51629,7 +51684,7 @@ var init_codex_native_skill_catalog = __esm(() => {
51629
51684
  });
51630
51685
 
51631
51686
  // src/lib/codex-plugin-skill-controls.ts
51632
- import { createHash as createHash10 } from "crypto";
51687
+ import { createHash as createHash11 } from "crypto";
51633
51688
  import { basename as basename6, dirname as dirname11, join as join20, relative as relative5, resolve as resolve11, sep as sep5 } from "path";
51634
51689
  import { lstatSync as lstatSync13, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as realpathSync6 } from "fs";
51635
51690
  function refuse2() {
@@ -51989,7 +52044,7 @@ function reviewCodexPluginControls(catalog, documents, cache3, cwd2, read2, rule
51989
52044
  const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document3 && rule?.enabled === false);
51990
52045
  const nativeSkill = { name: parsed.name, path: document3, pluginId: expectedPluginId, enabled: true };
51991
52046
  const denial = denials.find((item) => item.path === document3);
51992
- const explicitDeny = denial !== undefined && remotePluginId !== undefined && catalog.version === "codex-cli 0.160.0" && denial.name === parsed.name && denial.sha256 === createHash10("sha256").update(read2(document3)).digest("hex") && Array.isArray(rules) && !rules.some((rule) => (rule?.path === document3 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document3 && rule.enabled === false);
52047
+ const explicitDeny = denial !== undefined && remotePluginId !== undefined && catalog.version === "codex-cli 0.160.0" && denial.name === parsed.name && denial.sha256 === createHash11("sha256").update(read2(document3)).digest("hex") && Array.isArray(rules) && !rules.some((rule) => (rule?.path === document3 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document3 && rule.enabled === false);
51993
52048
  if (denial && !explicitDeny)
51994
52049
  refuse2();
51995
52050
  if (explicitDeny)
@@ -52082,7 +52137,7 @@ var init_codex_plugin_skill_controls = __esm(() => {
52082
52137
  });
52083
52138
 
52084
52139
  // src/lib/codex-native-skill-policy.ts
52085
- import { createHash as createHash11, randomUUID as randomUUID5 } from "crypto";
52140
+ import { createHash as createHash12, randomUUID as randomUUID5 } from "crypto";
52086
52141
  import { closeSync as closeSync7, constants as constants8, fstatSync as fstatSync7, fsyncSync as fsyncSync2, lstatSync as lstatSync14, mkdirSync as mkdirSync5, openSync as openSync7, readFileSync as readFileSync13, readSync as readSync5, readlinkSync as readlinkSync4, realpathSync as realpathSync7, renameSync as renameSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
52087
52142
  import { dirname as dirname12, isAbsolute as isAbsolute12, join as join21, resolve as resolve12 } from "path";
52088
52143
  import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
@@ -52094,7 +52149,7 @@ function codexNativeHookEnvelopeFromInput(input, event, inputBytes, inheritedFd)
52094
52149
  policy: input.native_skill_policy,
52095
52150
  sessionId: input.session_id,
52096
52151
  ...Object.hasOwn(input, "turn_id") ? { turnId: input.turn_id } : {},
52097
- hookInputSha256: createHash11("sha256").update(inputBytes).digest("hex"),
52152
+ hookInputSha256: createHash12("sha256").update(inputBytes).digest("hex"),
52098
52153
  ...inheritedFd !== undefined ? { inheritedFd: /^(0|[1-9]\d{0,9})$/.test(inheritedFd) ? Number(inheritedFd) : inheritedFd } : {}
52099
52154
  };
52100
52155
  }
@@ -52204,7 +52259,7 @@ function verifyCodexNativeBridgeDocument(path, expectedContent, expectedSha256)
52204
52259
  if (realpathSync7.native(path) !== path)
52205
52260
  refuse3("NATIVE_SKILL_POLICY_BRIDGE_UNVERIFIED", "the bridge document real path differs from its lexical path");
52206
52261
  const bytes = readBounded(path, MAX_BRIDGE_DOCUMENT_BYTES, "the bridge document");
52207
- const sha2562 = createHash11("sha256").update(bytes).digest("hex");
52262
+ const sha2562 = createHash12("sha256").update(bytes).digest("hex");
52208
52263
  if (!bytes.equals(Buffer.from(expectedContent, "utf8")) || sha2562 !== expectedSha256)
52209
52264
  refuse3("NATIVE_SKILL_POLICY_BRIDGE_UNVERIFIED", "the bridge document bytes differ from the managed bridge");
52210
52265
  return { path, sha256: sha2562 };
@@ -52679,7 +52734,7 @@ var init_codex_native_skill_policy = __esm(() => {
52679
52734
  });
52680
52735
 
52681
52736
  // src/lib/codex-settings-witness-v1.ts
52682
- import { createHash as createHash12 } from "crypto";
52737
+ import { createHash as createHash13 } from "crypto";
52683
52738
  function need3(value) {
52684
52739
  if (!value)
52685
52740
  throw new Error("Invalid Codex settings witness");
@@ -52723,8 +52778,8 @@ function numericTokens(text2) {
52723
52778
  }
52724
52779
  return result2;
52725
52780
  }
52726
- function canonical3(value, depth = 0, budget = { remaining: 65536 }) {
52727
- need3(depth <= 32 && --budget.remaining >= 0);
52781
+ function canonical3(value, depth = 0, budget2 = { remaining: 65536 }) {
52782
+ need3(depth <= 32 && --budget2.remaining >= 0);
52728
52783
  if (value === null)
52729
52784
  return ["null"];
52730
52785
  if (typeof value === "string")
@@ -52740,13 +52795,13 @@ function canonical3(value, depth = 0, budget = { remaining: 65536 }) {
52740
52795
  return ["date", value.toISOString()];
52741
52796
  }
52742
52797
  if (Array.isArray(value))
52743
- return ["array", value.map((child) => canonical3(child, depth + 1, budget))];
52798
+ return ["array", value.map((child) => canonical3(child, depth + 1, budget2))];
52744
52799
  need3(value && typeof value === "object");
52745
- return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical3(child, depth + 1, budget)])];
52800
+ return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical3(child, depth + 1, budget2)])];
52746
52801
  }
52747
- function hashCodexSettingsReplacement(text2, budget = { remaining: 256 * 1024 * 1024 }) {
52748
- need3(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
52749
- budget.remaining -= Buffer.byteLength(text2);
52802
+ function hashCodexSettingsReplacement(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
52803
+ need3(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
52804
+ budget2.remaining -= Buffer.byteLength(text2);
52750
52805
  let config;
52751
52806
  try {
52752
52807
  config = Bun.TOML.parse(text2);
@@ -52765,11 +52820,11 @@ function hashCodexSettingsReplacement(text2, budget = { remaining: 256 * 1024 *
52765
52820
  }
52766
52821
  return sha(`hasna.skills.codex-settings.v1\x00${JSON.stringify([canonical3(config), numericTokens(text2)])}`);
52767
52822
  }
52768
- function captureCodexSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
52769
- const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
52823
+ function captureCodexSettings(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
52824
+ const text2 = readNativeSettingsWitnessFile(path, budget2, "config.toml");
52770
52825
  return { path, hashMode: "codex-settings-v1", sha256: hashCodexSettingsReplacement(text2) };
52771
52826
  }
52772
- var sha = (text2) => createHash12("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
52827
+ var sha = (text2) => createHash13("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
52773
52828
  var init_codex_settings_witness_v1 = __esm(() => {
52774
52829
  init_claude_settings_witness();
52775
52830
  EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
@@ -52842,7 +52897,7 @@ function projectRegularCodexMcp(config, source) {
52842
52897
  var init_codex_mcp_discovery_projection = () => {};
52843
52898
 
52844
52899
  // src/lib/codex-settings-witness.ts
52845
- import { createHash as createHash13 } from "crypto";
52900
+ import { createHash as createHash14 } from "crypto";
52846
52901
  import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
52847
52902
  function need4(value) {
52848
52903
  if (!value)
@@ -52893,8 +52948,8 @@ function numericTokens2(text2) {
52893
52948
  }
52894
52949
  return result2.sort();
52895
52950
  }
52896
- function canonical4(value, depth = 0, budget = { remaining: 65536 }) {
52897
- need4(depth <= 32 && --budget.remaining >= 0);
52951
+ function canonical4(value, depth = 0, budget2 = { remaining: 65536 }) {
52952
+ need4(depth <= 32 && --budget2.remaining >= 0);
52898
52953
  if (value === null)
52899
52954
  return ["null"];
52900
52955
  if (typeof value === "string")
@@ -52910,9 +52965,9 @@ function canonical4(value, depth = 0, budget = { remaining: 65536 }) {
52910
52965
  return ["date", value.toISOString()];
52911
52966
  }
52912
52967
  if (Array.isArray(value))
52913
- return ["array", value.map((child) => canonical4(child, depth + 1, budget))];
52968
+ return ["array", value.map((child) => canonical4(child, depth + 1, budget2))];
52914
52969
  need4(isRecord3(value));
52915
- return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical4(child, depth + 1, budget)])];
52970
+ return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical4(child, depth + 1, budget2)])];
52916
52971
  }
52917
52972
  function normalize3(config, version = 2) {
52918
52973
  if (isRecord3(config.hooks)) {
@@ -53088,40 +53143,40 @@ function settingsDigest2(text2, version = 2) {
53088
53143
  normalize3(projected.config, version);
53089
53144
  return sha2(`hasna.skills.codex-settings.v${version}\x00${JSON.stringify([canonical4(projected.config), numericTokens2(projected.numericSource)])}`);
53090
53145
  }
53091
- function hashCodexSettingsReplacementV2(text2, budget = { remaining: 256 * 1024 * 1024 }) {
53092
- need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
53093
- budget.remaining -= Buffer.byteLength(text2);
53146
+ function hashCodexSettingsReplacementV2(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
53147
+ need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
53148
+ budget2.remaining -= Buffer.byteLength(text2);
53094
53149
  return settingsDigest2(text2);
53095
53150
  }
53096
- function captureCodexSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
53097
- const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
53151
+ function captureCodexSettingsV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
53152
+ const text2 = readNativeSettingsWitnessFile(path, budget2, "config.toml");
53098
53153
  return { path, hashMode: "codex-settings-v2", sha256: settingsDigest2(text2) };
53099
53154
  }
53100
- function readCodexSettingsPreimage(path, budget = { remaining: 2 * 1024 * 1024 }) {
53101
- return readNativeSettingsWitnessFile(path, budget, "config.toml");
53155
+ function readCodexSettingsPreimage(path, budget2 = { remaining: 2 * 1024 * 1024 }) {
53156
+ return readNativeSettingsWitnessFile(path, budget2, "config.toml");
53102
53157
  }
53103
53158
  function upgradeCodexSettingsWitness(previous, reviewedSettingsPath) {
53104
53159
  need4(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes" || previous.hashMode === "codex-settings-v1") && /^[a-f0-9]{64}$/.test(previous.sha256));
53105
- const budget = { remaining: 2 * 1024 * 1024 };
53106
- const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
53160
+ const budget2 = { remaining: 2 * 1024 * 1024 };
53161
+ const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget2, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget2, "config.toml");
53107
53162
  need4((previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before2) : sha2(before2)) === previous.sha256);
53108
53163
  const sha2562 = settingsDigest2(current);
53109
53164
  if (settingsDigest2(before2) !== sha2562)
53110
53165
  throw new Error("Codex non-preference settings changed; explicit discovery review required");
53111
53166
  return { path: previous.path, hashMode: "codex-settings-v2", sha256: sha2562 };
53112
53167
  }
53113
- function hashCodexSettingsReplacementV3(text2, budget = { remaining: 256 * 1024 * 1024 }) {
53114
- need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
53115
- budget.remaining -= Buffer.byteLength(text2);
53168
+ function hashCodexSettingsReplacementV3(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
53169
+ need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
53170
+ budget2.remaining -= Buffer.byteLength(text2);
53116
53171
  return settingsDigest2(text2, 3);
53117
53172
  }
53118
- function captureCodexSettingsV3(path, budget = { remaining: 256 * 1024 * 1024 }) {
53119
- return { path, hashMode: "codex-settings-v3", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget, "config.toml"), 3) };
53173
+ function captureCodexSettingsV3(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
53174
+ return { path, hashMode: "codex-settings-v3", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget2, "config.toml"), 3) };
53120
53175
  }
53121
53176
  function upgradeCodexSettingsWitnessV3(previous, reviewedSettingsPath) {
53122
53177
  need4(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || ["bytes", "codex-settings-v1", "codex-settings-v2"].includes(previous.hashMode)) && /^[a-f0-9]{64}$/.test(previous.sha256));
53123
- const budget = { remaining: 2 * 1024 * 1024 };
53124
- const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
53178
+ const budget2 = { remaining: 2 * 1024 * 1024 };
53179
+ const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget2, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget2, "config.toml");
53125
53180
  const original = previous.hashMode === "codex-settings-v2" ? settingsDigest2(before2) : previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before2) : sha2(before2);
53126
53181
  need4(original === previous.sha256);
53127
53182
  const sha2562 = settingsDigest2(current, 3);
@@ -53129,18 +53184,18 @@ function upgradeCodexSettingsWitnessV3(previous, reviewedSettingsPath) {
53129
53184
  throw new Error("Codex settings outside the reviewed V3 contract changed; explicit discovery review required");
53130
53185
  return { path: previous.path, hashMode: "codex-settings-v3", sha256: sha2562 };
53131
53186
  }
53132
- function hashCodexSettingsReplacementV4(text2, budget = { remaining: 256 * 1024 * 1024 }) {
53133
- need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
53134
- budget.remaining -= Buffer.byteLength(text2);
53187
+ function hashCodexSettingsReplacementV4(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
53188
+ need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
53189
+ budget2.remaining -= Buffer.byteLength(text2);
53135
53190
  return settingsDigest2(text2, 4);
53136
53191
  }
53137
- function captureCodexSettingsV4(path, budget = { remaining: 256 * 1024 * 1024 }) {
53138
- return { path, hashMode: "codex-settings-v4", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget, "config.toml"), 4) };
53192
+ function captureCodexSettingsV4(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
53193
+ return { path, hashMode: "codex-settings-v4", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget2, "config.toml"), 4) };
53139
53194
  }
53140
53195
  function upgradeCodexSettingsWitnessV4(previous, reviewedSettingsPath) {
53141
53196
  need4(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || ["bytes", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3"].includes(previous.hashMode)) && /^[a-f0-9]{64}$/.test(previous.sha256));
53142
- const budget = { remaining: 2 * 1024 * 1024 };
53143
- const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
53197
+ const budget2 = { remaining: 2 * 1024 * 1024 };
53198
+ const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget2, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget2, "config.toml");
53144
53199
  const original = previous.hashMode === "codex-settings-v3" ? settingsDigest2(before2, 3) : previous.hashMode === "codex-settings-v2" ? settingsDigest2(before2, 2) : previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before2) : sha2(before2);
53145
53200
  need4(original === previous.sha256);
53146
53201
  const sha2562 = settingsDigest2(current, 4);
@@ -53148,7 +53203,7 @@ function upgradeCodexSettingsWitnessV4(previous, reviewedSettingsPath) {
53148
53203
  throw new Error("Codex settings outside the reviewed V4 contract changed; explicit discovery review required");
53149
53204
  return { path: previous.path, hashMode: "codex-settings-v4", sha256: sha2562 };
53150
53205
  }
53151
- var sha2 = (text2) => createHash13("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
53206
+ var sha2 = (text2) => createHash14("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
53152
53207
  var init_codex_settings_witness = __esm(() => {
53153
53208
  init_codex_settings_witness_v1();
53154
53209
  init_codex_settings_witness_v1();
@@ -53247,7 +53302,7 @@ var init_managed_policy = __esm(() => {
53247
53302
  });
53248
53303
 
53249
53304
  // src/lib/agent-bridge.ts
53250
- import { createHash as createHash14 } from "crypto";
53305
+ import { createHash as createHash15 } from "crypto";
53251
53306
  import { lstatSync as lstatSync16, readFileSync as readFileSync14, readdirSync as readdirSync7 } from "fs";
53252
53307
  import { join as join25 } from "path";
53253
53308
  function isOwnedCliBridge(path, expectedPaths) {
@@ -53281,7 +53336,7 @@ Use the Skills CLI as the skill authority for this station.
53281
53336
  This bridge contains no skill payloads. Do not copy skill content into agent-native skill directories or load other native skill copies. If a Skills command refuses authority, selection, integrity, or native drift, report that refusal and use its repair guidance; do not substitute bundled or stale local content. Explicit local draft authoring remains available.
53282
53337
  `, CLI_BRIDGE_DIGEST, CLI_BRIDGE_FILES;
53283
53338
  var init_agent_bridge = __esm(() => {
53284
- CLI_BRIDGE_DIGEST = createHash14("sha256").update(markdown).digest("hex");
53339
+ CLI_BRIDGE_DIGEST = createHash15("sha256").update(markdown).digest("hex");
53285
53340
  CLI_BRIDGE_FILES = Object.freeze({
53286
53341
  "SKILL.md": markdown,
53287
53342
  ".hasna-skills.json": `${JSON.stringify({ managedBy: "@hasna/skills", kind: "cli-bridge", version: CLI_BRIDGE_VERSION, protocol: "selection-v1", contentSha256: CLI_BRIDGE_DIGEST }, null, 2)}
@@ -53593,31 +53648,44 @@ function sumiConfigPath(home) {
53593
53648
  return join26(sumiConfigDirectory(home), "sumi.json");
53594
53649
  }
53595
53650
  function renderSumiPlugin(command, profile) {
53651
+ return renderSumiPluginVersion(command, profile, false);
53652
+ }
53653
+ function isManagedSumiPlugin(text2, command, profile) {
53654
+ return text2 === renderSumiPlugin(command, profile) || text2 === renderSumiPluginVersion(command, profile, true);
53655
+ }
53656
+ function renderSumiPluginVersion(command, profile, legacy) {
53657
+ const failure = (message) => legacy ? `new Error(${JSON.stringify(message)})` : "refusal()";
53596
53658
  return `// Managed by @hasna/skills. Regenerate with skills hook install --agent sumi.
53597
53659
  import { spawn } from "node:child_process";
53598
53660
  const command = ${JSON.stringify(command)};
53599
53661
  const profile = ${JSON.stringify(profile)};
53600
- function context(input) {
53662
+ ${legacy ? "" : `function refusal() {
53663
+ const error = new Error("Skills verification blocked this request. Review the Sumi Skills hook configuration, then retry.");
53664
+ error.name = "SkillsHookRefusal";
53665
+ error.skillsHookRefusal = { version: 1, code: "SKILLS_HOOK_REFUSED" };
53666
+ return error;
53667
+ }
53668
+ `}function context(input) {
53601
53669
  return new Promise((resolve, reject) => {
53602
53670
  const child = spawn(command, ["hook", "user-prompt", "--agent", "sumi", "--selection-profile", profile], { cwd: input.cwd, stdio: ["pipe", "pipe", "pipe"] });
53603
53671
  const chunks = []; let bytes = 0, failure;
53604
- const timer = setTimeout(() => { failure = new Error("Skills prompt hook timed out"); child.kill("SIGKILL"); }, 15000);
53605
- 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); });
53672
+ const timer = setTimeout(() => { failure = ${failure("Skills prompt hook timed out")}; child.kill("SIGKILL"); }, 15000);
53673
+ child.stdout.on("data", chunk => { bytes += chunk.length; if (bytes > 1048576) { failure = ${failure("Skills prompt hook output exceeded its limit")}; child.kill("SIGKILL"); } else chunks.push(chunk); });
53606
53674
  child.stderr.on("data", () => {});
53607
53675
  child.stdin.on("error", () => {});
53608
- child.on("error", error => { clearTimeout(timer); reject(error); });
53676
+ child.on("error", error => { clearTimeout(timer); reject(${legacy ? "error" : "refusal()"}); });
53609
53677
  child.on("close", code => {
53610
53678
  clearTimeout(timer);
53611
- if (failure || code !== 0) return reject(failure ?? new Error("Skills prompt hook failed"));
53679
+ if (failure || code !== 0) return reject(failure ?? ${failure("Skills prompt hook failed")});
53612
53680
  try {
53613
53681
  const result = JSON.parse(Buffer.concat(chunks).toString("utf8"));
53614
- if (!result || typeof result !== "object" || Array.isArray(result)) throw new Error("Invalid Skills hook response");
53615
- if (result.decision === "block" || result.continue === false) throw new Error("Skills prompt hook refused");
53616
- if (Object.keys(result).length && (!result.hookSpecificOutput || result.hookSpecificOutput.hookEventName !== input.hook_event_name)) throw new Error("Invalid Skills hook response");
53682
+ if (!result || typeof result !== "object" || Array.isArray(result)) throw ${failure("Invalid Skills hook response")};
53683
+ if (result.decision === "block" || result.continue === false) throw ${failure("Skills prompt hook refused")};
53684
+ if (Object.keys(result).length && (!result.hookSpecificOutput || result.hookSpecificOutput.hookEventName !== input.hook_event_name)) throw ${failure("Invalid Skills hook response")};
53617
53685
  const text = result.hookSpecificOutput?.additionalContext ?? "";
53618
- if (typeof text !== "string") throw new Error("Invalid Skills prompt context");
53686
+ if (typeof text !== "string") throw ${failure("Invalid Skills prompt context")};
53619
53687
  resolve(text);
53620
- } catch (error) { reject(error); }
53688
+ } catch (error) { reject(${legacy ? "error" : "refusal()"}); }
53621
53689
  });
53622
53690
  child.stdin.end(JSON.stringify(input));
53623
53691
  });
@@ -53625,13 +53693,14 @@ function context(input) {
53625
53693
  export default {
53626
53694
  id: "local.hasna-skills-cli",
53627
53695
  async setup(ctx) {
53628
- if (!ctx?.session?.hook || !ctx?.session?.get || !ctx?.skill?.transform || !ctx?.tool?.hook) throw new Error("Unsupported Sumi native Skills contract");
53696
+ if (!ctx?.session?.hook || !ctx?.session?.get || !ctx?.skill?.transform || !ctx?.tool?.hook) throw ${failure("Unsupported Sumi native Skills contract")};
53629
53697
  const registrations = [];
53630
53698
  const sessions = new Set();
53631
53699
  async function input(sessionID, prompt, first) {
53632
53700
  // The Promise adapter unwraps single-data endpoint responses.
53633
- const session = await ctx.session.get({ sessionID });
53634
- 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");
53701
+ ${legacy ? "const session = await ctx.session.get({ sessionID });" : `let session;
53702
+ try { session = await ctx.session.get({ sessionID }); } catch { throw refusal(); }`}
53703
+ if (!session || session.id !== sessionID || typeof session.location?.directory !== "string" || (session.parentID !== undefined && typeof session.parentID !== "string") || session.parentID === sessionID) throw ${failure("Invalid Sumi session custody")};
53635
53704
  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 };
53636
53705
  }
53637
53706
  registrations.push(await ctx.skill.transform(editor => {
@@ -53640,11 +53709,11 @@ export default {
53640
53709
  // Native config transforms may add skills after this transform. Guard
53641
53710
  // both direct tool calls and prompt attachments at the consumption edge.
53642
53711
  registrations.push(await ctx.tool.hook("execute.before", event => {
53643
- if (event.tool === "skill" && event.input?.id !== "skills-cli") throw new Error("Native Sumi skill payload refused; use Skills CLI");
53712
+ if (event.tool === "skill" && event.input?.id !== "skills-cli") throw ${failure("Native Sumi skill payload refused; use Skills CLI")};
53644
53713
  }));
53645
53714
  registrations.push(await ctx.session.hook("prompt", async event => {
53646
- if (typeof event.prompt?.text !== "string") throw new Error("Invalid Sumi prompt");
53647
- 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");
53715
+ if (typeof event.prompt?.text !== "string") throw ${failure("Invalid Sumi prompt")};
53716
+ if (event.prompt.skills !== undefined && (!Array.isArray(event.prompt.skills) || event.prompt.skills.some(skill => skill?.id !== "skills-cli"))) throw ${failure("Native Sumi skill attachment refused; use Skills CLI")};
53648
53717
  await context(await input(event.sessionID, event.prompt.text, !sessions.has(event.sessionID)));
53649
53718
  sessions.add(event.sessionID);
53650
53719
  }));
@@ -53672,7 +53741,7 @@ var init_agent_sumi = __esm(() => {
53672
53741
 
53673
53742
  // src/lib/codex-hook-trust-files.ts
53674
53743
  import { closeSync as closeSync9, constants as constants10, fstatSync as fstatSync9, fsyncSync as fsyncSync3, lstatSync as lstatSync18, openSync as openSync9, readSync as readSync7, writeFileSync as writeFileSync5 } from "fs";
53675
- import { createHash as createHash15 } from "crypto";
53744
+ import { createHash as createHash16 } from "crypto";
53676
53745
  import { dirname as dirname13 } from "path";
53677
53746
  function need5(value, code) {
53678
53747
  if (!value)
@@ -53707,7 +53776,7 @@ function snapshot(file, privateFile = false, options = {}) {
53707
53776
  }
53708
53777
  need5(length === Number(before2.size) && sameStat(before2, fstatSync9(fd, { bigint: true })) && sameStat(before2, lstatSync18(file, { bigint: true })), "INPUT_CHANGED");
53709
53778
  const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
53710
- return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash15("sha256").update(content).digest("hex") };
53779
+ return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash16("sha256").update(content).digest("hex") };
53711
53780
  } finally {
53712
53781
  closeSync9(fd);
53713
53782
  }
@@ -53730,7 +53799,7 @@ var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs
53730
53799
  var init_codex_hook_trust_files = () => {};
53731
53800
 
53732
53801
  // src/lib/agent-integration.ts
53733
- import { createHash as createHash16, randomUUID as randomUUID6 } from "crypto";
53802
+ import { createHash as createHash17, randomUUID as randomUUID6 } from "crypto";
53734
53803
  import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
53735
53804
  import { existsSync as existsSync13, lstatSync as lstatSync19, statSync as statSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync15, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync5, realpathSync as realpathSync9, renameSync as renameSync3, rmdirSync as rmdirSync2, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4, chmodSync, openSync as openSync10, closeSync as closeSync10, fsyncSync as fsyncSync4, fstatSync as fstatSync10, readSync as readSync8, constants as constants11, linkSync as linkSync2 } from "fs";
53736
53805
  import { dirname as dirname14, join as join27, resolve as resolve14, relative as relative6, isAbsolute as isAbsolute13, sep as sep6 } from "path";
@@ -53927,7 +53996,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
53927
53996
  }
53928
53997
  }
53929
53998
  function treeHash(root) {
53930
- const hash2 = createHash16("sha256");
53999
+ const hash2 = createHash17("sha256");
53931
54000
  let bytes = 0, files = 0;
53932
54001
  function visit2(path) {
53933
54002
  const stat = lstatSync19(path);
@@ -54427,6 +54496,7 @@ function planAgentIntegration(options) {
54427
54496
  const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root) => root === input.sourceRoot || root.startsWith(input.sourceRoot + sep6) || input.sourceRoot.startsWith(root + sep6)) && codexDiscovery.sources.some((source) => source.path === join27(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
54428
54497
  assertCodexInstallationInputs(home, [options.projectDir ?? home], codexPluginSourceInputs.map((input) => input.sourceRoot));
54429
54498
  const changes = [];
54499
+ let observedSettings;
54430
54500
  for (const agent of [...new Set(options.agents)]) {
54431
54501
  if (!INTEGRATION_AGENTS.includes(agent))
54432
54502
  throw new Error(`Unsupported agent: ${agent}`);
@@ -54469,7 +54539,7 @@ function planAgentIntegration(options) {
54469
54539
  const pluginPath = join27(sumiConfigDirectory(home), "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
54470
54540
  const pluginAfter = renderSumiPlugin(command, profileId2);
54471
54541
  const priorCommand = policy.bridge?.commands?.sumi, priorProfile = policy.bridge?.profiles?.sumi ?? policy.profileId;
54472
- if (pluginBefore !== null && pluginBefore !== pluginAfter && !(typeof priorCommand === "string" && typeof priorProfile === "string" && pluginBefore === renderSumiPlugin(priorCommand, priorProfile)))
54542
+ if (pluginBefore !== null && pluginBefore !== pluginAfter && !(typeof priorCommand === "string" && typeof priorProfile === "string" && isManagedSumiPlugin(pluginBefore, priorCommand, priorProfile)))
54473
54543
  throw new Error("Refusing to overwrite a modified Sumi Skills plugin; preserve and review it first");
54474
54544
  if (pluginBefore !== pluginAfter)
54475
54545
  changes.push({ path: pluginPath, before: pluginBefore, after: pluginAfter });
@@ -54499,8 +54569,12 @@ function planAgentIntegration(options) {
54499
54569
  if (previous !== codexConfigBefore)
54500
54570
  throw new Error(`Configuration changed during planning: ${configPath}`);
54501
54571
  const next = disableReviewedCodexPluginNames(codexPathConfig, codexPluginSkills);
54502
- if (next !== (previous ?? ""))
54503
- changes.push({ path: configPath, before: previous, after: next });
54572
+ if (next !== (previous ?? "")) {
54573
+ if (previous !== null && isDeepStrictEqual7(Bun.TOML.parse(previous), Bun.TOML.parse(next))) {
54574
+ observedSettings = { path: configPath, before: previous };
54575
+ } else
54576
+ changes.push({ path: configPath, before: previous, after: next });
54577
+ }
54504
54578
  }
54505
54579
  }
54506
54580
  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(join27(home, ".codex/config.toml"), aliases))?.before === null ? null : sha3(readOptional(canonicalAgentPath(join27(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview;
@@ -54533,7 +54607,7 @@ function planAgentIntegration(options) {
54533
54607
  if (JSON.stringify(policy) !== JSON.stringify(nextPolicy))
54534
54608
  changes.push({ path: policyPath, before: previousPolicy, after: serializedPolicy });
54535
54609
  recheckRootAliases(aliases);
54536
- return { dataDir: dataDir3, profileId, changes, nativeSkills, ...observedNativeSources.length ? { observedNativeSources } : {}, ...nextPolicy.bridge.codexPluginSkillReview ? { codexPluginSkillReview: nextPolicy.bridge.codexPluginSkillReview } : {}, observedPolicy: { path: policyPath, before: previousPolicy }, discoveryBefore: discoveries, discoveryAfter, ...aliases.length ? { rootAliases: aliases } : {}, ...retainedAgents.length ? { retainedReviewChecks: { home, projectDir: options.projectDir ?? home, agents: retainedAgents } } : {} };
54610
+ return { dataDir: dataDir3, profileId, changes, nativeSkills, ...observedSettings ? { observedSettings } : {}, ...observedNativeSources.length ? { observedNativeSources } : {}, ...nextPolicy.bridge.codexPluginSkillReview ? { codexPluginSkillReview: nextPolicy.bridge.codexPluginSkillReview } : {}, observedPolicy: { path: policyPath, before: previousPolicy }, discoveryBefore: discoveries, discoveryAfter, ...aliases.length ? { rootAliases: aliases } : {}, ...retainedAgents.length ? { retainedReviewChecks: { home, projectDir: options.projectDir ?? home, agents: retainedAgents } } : {} };
54537
54611
  }
54538
54612
  function hookProjectionRefusal(reason) {
54539
54613
  throw new Error(`CLAUDE_MANAGED_HOOK_${reason}`);
@@ -54738,7 +54812,7 @@ function planAgentSettingsWitnessUpgrade(options) {
54738
54812
  const binding = policy.bridge?.discovery?.[options.agent];
54739
54813
  if (!binding || binding.agent !== options.agent || binding.method !== "reviewed")
54740
54814
  throw new Error("Settings witness upgrade requires an existing reviewed native binding");
54741
- const configPath = canonicalAgentPath(join27(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
54815
+ const configPath = canonicalAgentPath(options.agent === "sumi" ? sumiConfigPath(home) : join27(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
54742
54816
  const settings = readOptional(configPath);
54743
54817
  if (settings === null || sha3(settings) !== options.expectedSettingsSha256)
54744
54818
  throw new Error("Native settings preimage changed");
@@ -54764,7 +54838,19 @@ function planAgentSettingsWitnessUpgrade(options) {
54764
54838
  replaced.push(source);
54765
54839
  }
54766
54840
  }
54767
- const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 4 ? upgradeCodexSettingsWitnessV4(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
54841
+ if (options.agent === "sumi") {
54842
+ const preimage = readSumiSettingsPreimage(options.reviewedPreimage);
54843
+ for (const source of binding.sources) {
54844
+ if (source === previous || source.path !== configPath)
54845
+ continue;
54846
+ if (source.hashMode !== undefined || source.format !== "json" || !isDeepStrictEqual7(source.fields, [...SUMI_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
54847
+ throw new Error("Sumi settings witness upgrade found an unrecognized configuration witness");
54848
+ if (projectNativeDiscoveryFields(preimage, "json", source.fields, configPath) !== source.sha256)
54849
+ throw new Error("Reviewed preimage does not explain the Sumi discovery projection witness");
54850
+ replaced.push(source);
54851
+ }
54852
+ }
54853
+ const next = options.agent === "sumi" ? upgradeSumiSettingsWitness(previous, options.reviewedPreimage) : options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 4 ? upgradeCodexSettingsWitnessV4(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
54768
54854
  const rebound = [];
54769
54855
  for (const source of binding.sources) {
54770
54856
  if (!replaced.includes(source)) {
@@ -55125,7 +55211,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
55125
55211
  throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
55126
55212
  assertHermesProtection(home, config, command, profile, supervisor);
55127
55213
  } else if (agent === "sumi") {
55128
- if (JSON.stringify(config.permissions?.filter((rule) => rule.action === "skill")) !== JSON.stringify(SUMI_SKILL_PERMISSIONS) || readOptional(join27(sumiConfigDirectory(home), "plugins", "skills-cli.js")) !== renderSumiPlugin(command, profile))
55214
+ if (JSON.stringify(config.permissions?.filter((rule) => rule.action === "skill")) !== JSON.stringify(SUMI_SKILL_PERMISSIONS) || !isManagedSumiPlugin(readOptional(join27(sumiConfigDirectory(home), "plugins", "skills-cli.js")), command, profile))
55129
55215
  throw new Error("NATIVE_SKILL_DRIFT: Sumi bridge protection changed; run skills hook install");
55130
55216
  } else if (agent === "opencode") {
55131
55217
  if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(join27(home, ".config", "opencode", "plugins", "skills-cli.js")) !== renderOpenCodePlugin(command, profile))
@@ -55271,8 +55357,9 @@ function assertNativeExportAllowed(dataDir3 = getDataDirReadOnly()) {
55271
55357
  if (requiresCliSkillLoading(dataDir3))
55272
55358
  throw new Error("NATIVE_SKILL_EXPORT_DISABLED: this station loads skills through the Skills CLI; use skills sync --selection-profile <id>");
55273
55359
  }
55274
- var sha3 = (data) => createHash16("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
55360
+ var sha3 = (data) => createHash17("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
55275
55361
  var init_agent_integration = __esm(() => {
55362
+ init_sumi_settings_witness();
55276
55363
  init_codex_corpus_write();
55277
55364
  init_codex_plugin_skill_controls();
55278
55365
  init_codex_native_skill_policy();
@@ -56885,7 +56972,7 @@ var init_selection_resolver = __esm(() => {
56885
56972
  });
56886
56973
 
56887
56974
  // src/lib/plugin-projection.ts
56888
- import { createHash as createHash17 } from "crypto";
56975
+ import { createHash as createHash18 } from "crypto";
56889
56976
  import { posix } from "path";
56890
56977
  function pluginRefusal(message) {
56891
56978
  throw new SkillSelectionError("PLUGIN_ADMISSION_REFUSED", message);
@@ -57078,7 +57165,7 @@ function buildPluginProjection(entries) {
57078
57165
  files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
57079
57166
  return { manifest, payloads: manifest.payloads, files, witnesses: pluginFileWitnesses(files), originalTreeDigest, projectionTreeDigest: pluginTreeDigest(files), removed: removed.length ? pluginFileWitnesses(removed) : [] };
57080
57167
  }
57081
- var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash17("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
57168
+ var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash18("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
57082
57169
  var init_plugin_projection = __esm(() => {
57083
57170
  init_selection_cache();
57084
57171
  PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
@@ -57086,7 +57173,7 @@ var init_plugin_projection = __esm(() => {
57086
57173
  });
57087
57174
 
57088
57175
  // src/lib/plugin-projection-store.ts
57089
- import { createHash as createHash18, randomUUID as randomUUID7 } from "crypto";
57176
+ import { createHash as createHash19, randomUUID as randomUUID7 } from "crypto";
57090
57177
  import { constants as constants12, closeSync as closeSync11, fchmodSync, fstatSync as fstatSync11, fsyncSync as fsyncSync5, linkSync as linkSync3, lstatSync as lstatSync21, mkdirSync as mkdirSync10, openSync as openSync11, opendirSync as opendirSync4, readSync as readSync9, renameSync as renameSync6, rmdirSync as rmdirSync3, rmSync as rmSync4, unlinkSync as unlinkSync5, writeSync as writeSync2 } from "fs";
57091
57178
  import { dirname as dirname16, isAbsolute as isAbsolute14, join as join33, parse as parse5, resolve as resolve15 } from "path";
57092
57179
  function stat(path) {
@@ -57424,7 +57511,7 @@ function pluginExecutableDigest(path) {
57424
57511
  const opened = fstatSync11(fd, { bigint: true });
57425
57512
  same3(before2, opened);
57426
57513
  fileShape(opened, maximum, "executable");
57427
- const hash2 = createHash18("sha256"), buffer = new Uint8Array(64 * 1024);
57514
+ const hash2 = createHash19("sha256"), buffer = new Uint8Array(64 * 1024);
57428
57515
  let remaining = Number(opened.size);
57429
57516
  while (remaining > 0) {
57430
57517
  const count = readSync9(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
@@ -58007,7 +58094,7 @@ var init_plugin_discovery = __esm(() => {
58007
58094
  });
58008
58095
 
58009
58096
  // src/lib/claude-marketplace-registry.ts
58010
- import { createHash as createHash19 } from "crypto";
58097
+ import { createHash as createHash20 } from "crypto";
58011
58098
  import { closeSync as closeSync13, constants as constants14, fstatSync as fstatSync13, lstatSync as lstatSync23, openSync as openSync13, readSync as readSync11 } from "fs";
58012
58099
  import { basename as basename9, dirname as dirname18, isAbsolute as isAbsolute17, resolve as resolve18 } from "path";
58013
58100
  function need6(value, reason) {
@@ -58027,13 +58114,13 @@ function parents2(path) {
58027
58114
  return result2;
58028
58115
  }
58029
58116
  }
58030
- function readRegistry2(path, budget) {
58117
+ function readRegistry2(path, budget2) {
58031
58118
  absolutePath3(path);
58032
58119
  need6(basename9(path) === "known_marketplaces.json", "requires known_marketplaces.json");
58033
- need6(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
58120
+ need6(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
58034
58121
  const ancestors2 = parents2(path), initial2 = lstatSync23(path, { bigint: true });
58035
58122
  need6(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
58036
- need6(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
58123
+ need6(initial2.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
58037
58124
  const fd = openSync13(path, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
58038
58125
  try {
58039
58126
  const opened = fstatSync13(fd, { bigint: true });
@@ -58052,7 +58139,7 @@ function readRegistry2(path, budget) {
58052
58139
  const now3 = lstatSync23(ancestor, { bigint: true });
58053
58140
  need6(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
58054
58141
  }
58055
- budget.remaining -= length;
58142
+ budget2.remaining -= length;
58056
58143
  try {
58057
58144
  return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
58058
58145
  } catch {
@@ -58169,18 +58256,18 @@ function normalizeRow(row, version = 1) {
58169
58256
  need6(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
58170
58257
  row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
58171
58258
  }
58172
- function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
58173
- const value = parse6(readRegistry2(path, budget));
58259
+ function captureClaudeMarketplaceRegistry(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
58260
+ const value = parse6(readRegistry2(path, budget2));
58174
58261
  for (const [, row] of value.entries)
58175
58262
  normalizeRow(row);
58176
- const sha2562 = createHash19("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
58263
+ const sha2562 = createHash20("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
58177
58264
  return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
58178
58265
  }
58179
- function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
58180
- const value = parse6(readRegistry2(path, budget));
58266
+ function captureClaudeMarketplaceRegistryV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
58267
+ const value = parse6(readRegistry2(path, budget2));
58181
58268
  for (const [, row] of value.entries)
58182
58269
  normalizeRow(row, 2);
58183
- const sha2562 = createHash19("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
58270
+ const sha2562 = createHash20("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
58184
58271
  return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
58185
58272
  }
58186
58273
  var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, 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, field = (object6, key) => object6.entries.find(([name]) => name === key)?.[1];
@@ -58406,7 +58493,7 @@ var init_codex_hook_additions_review = __esm(() => {
58406
58493
  });
58407
58494
 
58408
58495
  // src/lib/codex-hook-discovery-recovery.ts
58409
- import { createHash as createHash20 } from "crypto";
58496
+ import { createHash as createHash21 } from "crypto";
58410
58497
  import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
58411
58498
  function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, additions) {
58412
58499
  const journalHooks = hooks.map(({ key, currentHash }) => ({ key, currentHash }));
@@ -58456,7 +58543,7 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
58456
58543
  need5(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
58457
58544
  return true;
58458
58545
  }
58459
- var sha4 = (text3) => createHash20("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
58546
+ var sha4 = (text3) => createHash21("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
58460
58547
  var init_codex_hook_discovery_recovery = __esm(() => {
58461
58548
  init_codex_hook_trust_files();
58462
58549
  init_codex_hook_trust_layout();
@@ -58467,7 +58554,7 @@ var init_codex_hook_discovery_recovery = __esm(() => {
58467
58554
  });
58468
58555
 
58469
58556
  // src/lib/agent-discovery.ts
58470
- import { createHash as createHash21 } from "crypto";
58557
+ import { createHash as createHash22 } from "crypto";
58471
58558
  import { lstatSync as lstatSync24, readFileSync as readFileSync20, readdirSync as readdirSync11, realpathSync as realpathSync10 } from "fs";
58472
58559
  import { basename as basename10, dirname as dirname19, isAbsolute as isAbsolute19, join as join36, resolve as resolve19, sep as sep7 } from "path";
58473
58560
  import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
@@ -58508,33 +58595,45 @@ function projectNativeDiscoveryFields(text3, format, fields2, path) {
58508
58595
  throw new Error("Expected native discovery configuration object");
58509
58596
  return digest(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object6[field2] ?? null]))));
58510
58597
  }
58511
- function isSupersededCodexProjection(agent, configPath, source) {
58598
+ function isSupersededSettingsProjection(agent, configPath, source) {
58599
+ if (agent === "sumi")
58600
+ return source.path === configPath && source.format === "json" && isDeepStrictEqual11(source.fields, [...SUMI_DISCOVERY_PROJECTION_FIELDS]);
58512
58601
  return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual11(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
58513
58602
  }
58514
- function supersedesCodexProjection(sources, configPath) {
58515
- return sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")));
58603
+ function supersedesSettingsProjection(agent, sources, configPath) {
58604
+ if (agent === "sumi")
58605
+ return sources.some((source) => source.path === configPath && source.hashMode === "sumi-settings-v1");
58606
+ return agent === "codex" && sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")));
58516
58607
  }
58517
- function projected(source, changes, budget = discoveryByteBudget()) {
58608
+ function projected(source, changes, budget2 = discoveryByteBudget()) {
58609
+ if (source.hashMode === "sumi-settings-v1") {
58610
+ if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
58611
+ throw new Error("Sumi settings witnesses require exact typed metadata");
58612
+ const current = captureSumiSettings(source.path, budget2).sha256;
58613
+ if (current !== source.sha256)
58614
+ throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
58615
+ return changes?.has(source.path) ? hashSumiSettingsReplacement(changes.get(source.path), budget2) : current;
58616
+ }
58518
58617
  if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) {
58519
58618
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
58520
58619
  throw new Error("Codex settings witnesses require exact typed metadata");
58521
- const current = (source.hashMode === "codex-settings-v4" ? captureCodexSettingsV4 : source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
58620
+ const current = (source.hashMode === "codex-settings-v4" ? captureCodexSettingsV4 : source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget2).sha256;
58522
58621
  if (current !== source.sha256)
58523
58622
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
58524
- return changes?.has(source.path) ? (source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
58623
+ return changes?.has(source.path) ? (source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget2) : current;
58525
58624
  }
58526
58625
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
58527
58626
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
58528
58627
  throw new Error("Claude settings witnesses require exact typed metadata");
58529
- const current = (source.hashMode === "claude-settings-v3" ? captureClaudeSettingsV3 : source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget).sha256;
58628
+ const current = (source.hashMode === "claude-settings-v3" ? captureClaudeSettingsV3 : source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget2).sha256;
58530
58629
  if (current !== source.sha256)
58531
58630
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
58532
- return changes?.has(source.path) ? (source.hashMode === "claude-settings-v3" ? hashClaudeSettingsReplacementV3 : source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget) : current;
58631
+ return changes?.has(source.path) ? (source.hashMode === "claude-settings-v3" ? hashClaudeSettingsReplacementV3 : source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget2) : current;
58533
58632
  }
58534
58633
  if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") {
58535
58634
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256) || changes?.has(source.path))
58536
58635
  throw new Error("Claude marketplace witnesses require an exact reviewed registry without synthetic changes");
58537
- const sha2562 = (source.hashMode === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : captureClaudeMarketplaceRegistry)(source.path, budget).sha256;
58636
+ const sha2562 = (source.hashMode === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : captureClaudeMarketplaceRegistry)(source.path, budget2).sha256;
58538
58637
  if (sha2562 !== source.sha256)
58539
58638
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
58540
58639
  return sha2562;
@@ -58552,8 +58651,8 @@ function projected(source, changes, budget = discoveryByteBudget()) {
58552
58651
  if (source.format !== undefined || source.fields !== undefined)
58553
58652
  throw new Error("Raw discovery witnesses cannot project configuration fields");
58554
58653
  if (source.hashMode === "path-bytes")
58555
- return hashDiscoveryPathFile(source.path, budget, changes);
58556
- return hashRawDiscoveryFile(source.path, budget, changes);
58654
+ return hashDiscoveryPathFile(source.path, budget2, changes);
58655
+ return hashRawDiscoveryFile(source.path, budget2, changes);
58557
58656
  }
58558
58657
  const text3 = read2(source.path, changes);
58559
58658
  if (text3 === null)
@@ -58701,7 +58800,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
58701
58800
  verifyDiscoveryDirectories(projected2, installationRoots);
58702
58801
  }
58703
58802
  const absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root2) => !lstatSync24(root2, { throwIfNoEntry: false }))];
58704
- const budget = discoveryByteBudget();
58803
+ const budget2 = discoveryByteBudget();
58705
58804
  for (const source of binding.sources) {
58706
58805
  assertMarketplaceBinding(binding, source);
58707
58806
  if (source.hashMode === "claude-plugin-registry" && binding.agent !== "claude")
@@ -58718,7 +58817,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
58718
58817
  safe4(source.path);
58719
58818
  continue;
58720
58819
  }
58721
- const current = projected(source, undefined, budget);
58820
+ const current = projected(source, undefined, budget2);
58722
58821
  if (current !== source.sha256 && !verifiesCodexHookDiscoverySource(binding, source, current, codexRecovery))
58723
58822
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
58724
58823
  }
@@ -58752,6 +58851,8 @@ function codexInstallationRoots(binding) {
58752
58851
  });
58753
58852
  }
58754
58853
  function assertMarketplaceBinding(binding, source) {
58854
+ if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename10(source.path) !== "sumi.json"))
58855
+ throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
58755
58856
  if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename10(source.path) !== "config.toml"))
58756
58857
  throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
58757
58858
  if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename10(source.path) !== "settings.json"))
@@ -58760,13 +58861,13 @@ function assertMarketplaceBinding(binding, source) {
58760
58861
  throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
58761
58862
  }
58762
58863
  function rebindAgentDiscovery(binding, changes) {
58763
- const budget = discoveryByteBudget();
58864
+ const budget2 = discoveryByteBudget();
58764
58865
  const installationRoots = codexInstallationRoots(binding), absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredCodexRoots(binding).filter((root2) => !lstatSync24(root2, { throwIfNoEntry: false }))];
58765
58866
  const rebound = { ...binding, sources: binding.sources.map((source) => {
58766
58867
  assertMarketplaceBinding(binding, source);
58767
58868
  if (!changes.has(source.path) && (installationRoots.some((root2) => source.path.startsWith(root2 + sep7)) || absentRoots.some((root2) => source.path.startsWith(root2 + sep7)) && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && [undefined, "bytes"].includes(source.hashMode)))
58768
58869
  return source;
58769
- const sha2562 = projected(source, changes, budget);
58870
+ const sha2562 = projected(source, changes, budget2);
58770
58871
  if (!changes.has(source.path) && sha2562 !== source.sha256)
58771
58872
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
58772
58873
  return { ...source, sha256: sha2562 };
@@ -58844,7 +58945,7 @@ function resolveAgentDiscovery(options) {
58844
58945
  if (agent === "hermes")
58845
58946
  assertHermesEnvironment(home);
58846
58947
  const configPath = agentDiscoveryConfigPath(home, agent);
58847
- 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"]);
58948
+ 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" ? [...SUMI_DISCOVERY_PROJECTION_FIELDS] : ["version"]);
58848
58949
  const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
58849
58950
  const unresolved = (detail) => {
58850
58951
  throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
@@ -58941,9 +59042,9 @@ function resolveAgentDiscovery(options) {
58941
59042
  verifyAgentDiscovery(retained);
58942
59043
  if (!retained.sources.some((source) => source.path === canonical6(configPath) && source.format === undefined && source.fields === undefined))
58943
59044
  unresolved("retained review is missing the full agent configuration source");
58944
- if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical6(configPath)))
59045
+ if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical6(configPath)))
58945
59046
  unresolved("retained settings witness names another configuration source");
58946
- const covered = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
59047
+ const covered = supersedesSettingsProjection(agent, retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical6(configPath), source)) : sources;
58947
59048
  if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual11(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
58948
59049
  unresolved("retained review is missing current runtime discovery coverage");
58949
59050
  return retained;
@@ -58958,11 +59059,11 @@ function resolveAgentDiscovery(options) {
58958
59059
  if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
58959
59060
  throw new Error("Explicit discovery reviews require full source-file hashes");
58960
59061
  verifyAgentDiscovery(supplied);
58961
- if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical6(configPath)))
58962
- throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
59062
+ if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical6(configPath)))
59063
+ throw new Error("Semantic settings witnesses must name the configured agent configuration source");
58963
59064
  if (!review.sources.some((source) => source.path === canonical6(configPath)))
58964
59065
  throw new Error("Discovery review must include the agent configuration source");
58965
- const reviewedSources = supersedesCodexProjection(review.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
59066
+ const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical6(configPath), source)) : sources;
58966
59067
  return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...reviewedSources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
58967
59068
  }
58968
59069
  function plugin(root2) {
@@ -59077,8 +59178,9 @@ function resolveAgentDiscovery(options) {
59077
59178
  }
59078
59179
  return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join36(home, ".hermes/plugins"), join36(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
59079
59180
  }
59080
- var digest = (text3) => createHash21("sha256").update(text3).digest("hex");
59181
+ var digest = (text3) => createHash22("sha256").update(text3).digest("hex");
59081
59182
  var init_agent_discovery = __esm(() => {
59183
+ init_sumi_settings_witness();
59082
59184
  init_agent_policy_limits();
59083
59185
  init_agent_hermes();
59084
59186
  init_agent_discovery_directories();
@@ -62016,7 +62118,7 @@ var init_remote_workspace_selection = __esm(() => {
62016
62118
  });
62017
62119
 
62018
62120
  // src/lib/remote-private-publications.ts
62019
- import { createHash as createHash22 } from "crypto";
62121
+ import { createHash as createHash23 } from "crypto";
62020
62122
  function checkedPublicationDeclaration(value) {
62021
62123
  if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
62022
62124
  return bad();
@@ -62036,7 +62138,7 @@ function checkedPublicationView(value, skillId, intentId, declaration) {
62036
62138
  return invalid3();
62037
62139
  return Object.freeze({ ...value });
62038
62140
  }
62039
- async function boundedJson(url, init, token, mutation, budget = 15000, signal) {
62141
+ async function boundedJson(url, init, token, mutation, budget2 = 15000, signal) {
62040
62142
  const controller = new AbortController;
62041
62143
  let reader;
62042
62144
  let response;
@@ -62091,7 +62193,7 @@ async function boundedJson(url, init, token, mutation, budget = 15000, signal) {
62091
62193
  controller.abort();
62092
62194
  reject2(timeout);
62093
62195
  };
62094
- timer = setTimeout(abort, Math.max(1, Math.min(15000, budget)));
62196
+ timer = setTimeout(abort, Math.max(1, Math.min(15000, budget2)));
62095
62197
  signal?.addEventListener("abort", abort, { once: true });
62096
62198
  })]);
62097
62199
  } catch (error) {
@@ -62277,7 +62379,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures, PrivatePublicationError, bad = () =
62277
62379
  throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
62278
62380
  }, invalid3 = () => {
62279
62381
  throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
62280
- }, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record5 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record5(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash22("sha256").update(bytes).digest("hex");
62382
+ }, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record5 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record5(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash23("sha256").update(bytes).digest("hex");
62281
62383
  var init_remote_private_publications = __esm(() => {
62282
62384
  init_fleet_credentials();
62283
62385
  init_remote_workspace_selection();
@@ -81666,7 +81768,7 @@ var init_v4 = __esm(() => {
81666
81768
  });
81667
81769
 
81668
81770
  // src/lib/canonical-json.ts
81669
- import { createHash as createHash23 } from "crypto";
81771
+ import { createHash as createHash24 } from "crypto";
81670
81772
  function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
81671
81773
  return canonicalJsonAtDepth(value, maximumBytes, 64);
81672
81774
  }
@@ -81710,7 +81812,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
81710
81812
  return visit3(value, 0);
81711
81813
  }
81712
81814
  function canonicalJsonSha256(value, maximumBytes) {
81713
- return createHash23("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
81815
+ return createHash24("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
81714
81816
  }
81715
81817
  var init_canonical_json = () => {};
81716
81818
 
@@ -81889,7 +81991,7 @@ function parseRecurringResult(action, value, input2, identity6) {
81889
81991
  }
81890
81992
  return result2;
81891
81993
  }
81892
- var RecurringInputError, RemoteRecurringUnavailableError, RemoteRecurringReadError, RemoteRecurringUnconfirmedError, failures2, RemoteRecurringError, uuid10, instant2, integer2, digest2, list, inputs, capabilityNames, budget, period, preview, consent, refusal2, occurrence, revocation, page = (item) => exports_external.object({ contractVersion: exports_external.literal(1), items: exports_external.array(item).max(100), nextCursor: exports_external.string().min(1).max(2048).nullable() }), results;
81994
+ var RecurringInputError, RemoteRecurringUnavailableError, RemoteRecurringReadError, RemoteRecurringUnconfirmedError, failures2, RemoteRecurringError, uuid10, instant2, integer2, digest2, list, inputs, capabilityNames, budget2, period, preview, consent, refusal2, occurrence, revocation, page = (item) => exports_external.object({ contractVersion: exports_external.literal(1), items: exports_external.array(item).max(100), nextCursor: exports_external.string().min(1).max(2048).nullable() }), results;
81893
81995
  var init_remote_recurring = __esm(() => {
81894
81996
  init_v4();
81895
81997
  init_canonical_json();
@@ -81975,7 +82077,7 @@ var init_remote_recurring = __esm(() => {
81975
82077
  occurrences: "recurring.occurrences",
81976
82078
  revoke: "recurring.revoke"
81977
82079
  };
81978
- budget = exports_external.object({ reservedCredits: integer2, settledCredits: integer2, admittedOccurrences: integer2 });
82080
+ budget2 = exports_external.object({ reservedCredits: integer2, settledCredits: integer2, admittedOccurrences: integer2 });
81979
82081
  period = exports_external.object({ startsAt: instant2, endsAt: instant2 });
81980
82082
  preview = exports_external.object({
81981
82083
  contractVersion: exports_external.literal(1),
@@ -81997,8 +82099,8 @@ var init_remote_recurring = __esm(() => {
81997
82099
  state: exports_external.enum(["active", "revoked", "expired"]),
81998
82100
  activatedAt: instant2,
81999
82101
  revokedAt: instant2.nullable(),
82000
- total: budget,
82001
- currentPeriod: budget.extend(period.shape).nullable(),
82102
+ total: budget2,
82103
+ currentPeriod: budget2.extend(period.shape).nullable(),
82002
82104
  nextDueAt: instant2.nullable()
82003
82105
  });
82004
82106
  refusal2 = exports_external.enum([
@@ -83624,7 +83726,7 @@ var init_remote_auth = __esm(() => {
83624
83726
  });
83625
83727
 
83626
83728
  // src/lib/sign-in.ts
83627
- import { createHash as createHash24 } from "crypto";
83729
+ import { createHash as createHash25 } from "crypto";
83628
83730
  import { chmodSync as chmodSync3, mkdirSync as mkdirSync13, readFileSync as readFileSync25, readdirSync as readdirSync14, renameSync as renameSync9, unlinkSync as unlinkSync7, writeFileSync as writeFileSync12 } from "fs";
83629
83731
  import { basename as basename14, dirname as dirname23, join as join41 } from "path";
83630
83732
  function isRecord7(value) {
@@ -83775,7 +83877,7 @@ function pendingDeviceSignInStem(env3) {
83775
83877
  }
83776
83878
  function pendingDeviceSignInPath(origin, env3 = process.env) {
83777
83879
  const { dir, stem } = pendingDeviceSignInStem(env3);
83778
- return join41(dir, `${stem}-${createHash24("sha256").update(origin).digest("hex").slice(0, 16)}.json`);
83880
+ return join41(dir, `${stem}-${createHash25("sha256").update(origin).digest("hex").slice(0, 16)}.json`);
83779
83881
  }
83780
83882
  function savePendingDeviceSignIn(origin, start, env3 = process.env, now3 = Date.now()) {
83781
83883
  const path = pendingDeviceSignInPath(origin, env3);
@@ -84479,7 +84581,7 @@ function optionPrefix(program2, args) {
84479
84581
  }
84480
84582
 
84481
84583
  // src/lib/revision.ts
84482
- import { createHash as createHash25 } from "crypto";
84584
+ import { createHash as createHash26 } from "crypto";
84483
84585
  function revisionIdOf(content) {
84484
84586
  const canonicalContent = {
84485
84587
  slug: content.slug,
@@ -84500,7 +84602,7 @@ function revisionIdOf(content) {
84500
84602
  canonicalContent.replacementSlug = content.replacementSlug ?? null;
84501
84603
  }
84502
84604
  const canonical6 = JSON.stringify(canonicalContent);
84503
- return createHash25("sha256").update(canonical6).digest("hex");
84605
+ return createHash26("sha256").update(canonical6).digest("hex");
84504
84606
  }
84505
84607
  var REVISION_ID_PATTERN;
84506
84608
  var init_revision = __esm(() => {
@@ -84949,7 +85051,7 @@ var init_pull = __esm(() => {
84949
85051
  });
84950
85052
 
84951
85053
  // src/lib/skill-context.ts
84952
- import { createHash as createHash26 } from "crypto";
85054
+ import { createHash as createHash27 } from "crypto";
84953
85055
  import { resolve as resolve22 } from "path";
84954
85056
  function words2(value) {
84955
85057
  return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
@@ -85042,7 +85144,7 @@ ${content}`;
85042
85144
  `);
85043
85145
  const receipt = {
85044
85146
  schemaVersion: 1,
85045
- id: createHash26("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
85147
+ id: createHash27("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
85046
85148
  profileId: profile.profileId,
85047
85149
  profileRevision: profile.profileRevision,
85048
85150
  authority: profile.authority,
@@ -85064,7 +85166,7 @@ var init_skill_context = __esm(() => {
85064
85166
  });
85065
85167
 
85066
85168
  // src/lib/session-reconciliation.ts
85067
- import { createHash as createHash27 } from "crypto";
85169
+ import { createHash as createHash28 } from "crypto";
85068
85170
  import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
85069
85171
  function exactTimestamp(value) {
85070
85172
  const parsed = value === undefined ? Number.NaN : Date.parse(value);
@@ -85204,7 +85306,7 @@ async function reconcileSkillSession(input2, options = {}) {
85204
85306
  const result2 = replaceSkillSession(skillSessionSnapshotBinding(snapshot2), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
85205
85307
  return { applied: true, plan, planDigest, ...result2 };
85206
85308
  }
85207
- var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash27("sha256").update(JSON.stringify(value)).digest("hex");
85309
+ var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash28("sha256").update(JSON.stringify(value)).digest("hex");
85208
85310
  var init_session_reconciliation = __esm(() => {
85209
85311
  init_profile_client();
85210
85312
  init_selection_cache();
@@ -89846,7 +89948,7 @@ __export(exports_selected_run, {
89846
89948
  prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
89847
89949
  executeSelectedLocal: () => executeSelectedLocal
89848
89950
  });
89849
- import { createHash as createHash28 } from "crypto";
89951
+ import { createHash as createHash29 } from "crypto";
89850
89952
  import { spawn as spawn3 } from "child_process";
89851
89953
  import { mkdirSync as mkdirSync16, mkdtempSync as mkdtempSync4, writeFileSync as writeFileSync16, realpathSync as realpathSync14 } from "fs";
89852
89954
  import { dirname as dirname25, join as join49, resolve as resolve23 } from "path";
@@ -89972,7 +90074,7 @@ async function executeSelectedLocal(selected, options = {}) {
89972
90074
  selection: selection2,
89973
90075
  target: "local",
89974
90076
  runtime: runtimeName,
89975
- inputDigest: `sha256:${createHash28("sha256").update(input2).digest("hex")}`,
90077
+ inputDigest: `sha256:${createHash29("sha256").update(input2).digest("hex")}`,
89976
90078
  runDirectory,
89977
90079
  ...executionGrant ? { executionGrant } : {},
89978
90080
  ...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
@@ -94189,7 +94291,7 @@ var init_runs = __esm(() => {
94189
94291
  });
94190
94292
 
94191
94293
  // src/lib/run-state.ts
94192
- import { createHash as createHash29, randomBytes } from "crypto";
94294
+ import { createHash as createHash30, randomBytes } from "crypto";
94193
94295
  import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync34, readdirSync as readdirSync18, statSync as statSync17, writeFileSync as writeFileSync17 } from "fs";
94194
94296
  import { extname, join as join50, relative as relative8 } from "path";
94195
94297
  function createSkillRun(params, targetDir = process.cwd()) {
@@ -94326,7 +94428,7 @@ function collectRunArtifacts(context) {
94326
94428
  artifacts.push({
94327
94429
  path: toProjectRelative(context.targetDir, path),
94328
94430
  mime: mimeForPath(path),
94329
- sha256: createHash29("sha256").update(bytes).digest("hex"),
94431
+ sha256: createHash30("sha256").update(bytes).digest("hex"),
94330
94432
  sizeBytes: stat2.size
94331
94433
  });
94332
94434
  }
@@ -109574,7 +109676,7 @@ var init_schedule_tools = __esm(() => {
109574
109676
  });
109575
109677
 
109576
109678
  // src/lib/native-storage.ts
109577
- import { createHash as createHash30, createHmac as createHmac3 } from "crypto";
109679
+ import { createHash as createHash31, createHmac as createHmac3 } from "crypto";
109578
109680
  import {
109579
109681
  existsSync as existsSync32,
109580
109682
  mkdirSync as mkdirSync22,
@@ -109651,7 +109753,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
109651
109753
  files.push({
109652
109754
  path: relativePath,
109653
109755
  sizeBytes: bytes.byteLength,
109654
- sha256: createHash30("sha256").update(bytes).digest("hex"),
109756
+ sha256: createHash31("sha256").update(bytes).digest("hex"),
109655
109757
  ...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
109656
109758
  });
109657
109759
  }
@@ -110833,7 +110935,7 @@ var init_remote_account2 = __esm(() => {
110833
110935
  });
110834
110936
 
110835
110937
  // src/cli/commands/reviewed-runtime-lock.ts
110836
- import { createHash as createHash31 } from "crypto";
110938
+ import { createHash as createHash32 } from "crypto";
110837
110939
  function row(value) {
110838
110940
  if (!value || typeof value !== "object" || Array.isArray(value))
110839
110941
  throw new Error("REVIEWED_LOCK_SHAPE_INVALID");
@@ -110887,7 +110989,7 @@ async function metadata(name, context2) {
110887
110989
  async function validateReviewedRuntimeLock(bytes, sha2562, context2) {
110888
110990
  if (!/^[a-f0-9]{64}$/.test(sha2562))
110889
110991
  throw new Error("REVIEWED_LOCK_SHA256_INVALID");
110890
- if (bytes.byteLength > MAX_LOCK_BYTES || createHash31("sha256").update(bytes).digest("hex") !== sha2562)
110992
+ if (bytes.byteLength > MAX_LOCK_BYTES || createHash32("sha256").update(bytes).digest("hex") !== sha2562)
110891
110993
  throw new Error("REVIEWED_LOCK_HASH_MISMATCH");
110892
110994
  if (!Number.isSafeInteger(context2.minReleaseAge) || context2.minReleaseAge < 1)
110893
110995
  throw new Error("REVIEWED_LOCK_RELEASE_AGE_REQUIRED");
@@ -110964,7 +111066,7 @@ var init_reviewed_runtime_lock = __esm(() => {
110964
111066
  });
110965
111067
 
110966
111068
  // src/cli/commands/runtime-copyfile.ts
110967
- import { createHash as createHash32, randomUUID as randomUUID10 } from "crypto";
111069
+ import { createHash as createHash33, randomUUID as randomUUID10 } from "crypto";
110968
111070
  import { Readable } from "stream";
110969
111071
  import { createGunzip as createGunzip2 } from "zlib";
110970
111072
  import {
@@ -110988,7 +111090,7 @@ function object10(value, code2) {
110988
111090
  return value;
110989
111091
  }
110990
111092
  function hash5(bytes) {
110991
- return createHash32("sha256").update(bytes).digest("hex");
111093
+ return createHash33("sha256").update(bytes).digest("hex");
110992
111094
  }
110993
111095
  function isWithin(parent, child) {
110994
111096
  const rel = relative10(parent, child);
@@ -111139,7 +111241,7 @@ function verifyIntegrity(bytes, integrity) {
111139
111241
  const match = /^sha512-([A-Za-z0-9+/]+={0,2})$/.exec(integrity);
111140
111242
  if (!match)
111141
111243
  throw new Error("REGISTRY_INTEGRITY_UNSUPPORTED");
111142
- const actual = createHash32("sha512").update(bytes).digest("base64");
111244
+ const actual = createHash33("sha512").update(bytes).digest("base64");
111143
111245
  if (actual !== match[1])
111144
111246
  throw new Error("TARBALL_INTEGRITY_MISMATCH");
111145
111247
  }
@@ -112243,7 +112345,7 @@ var exports_runtime = {};
112243
112345
  __export(exports_runtime, {
112244
112346
  registerRuntime: () => registerRuntime
112245
112347
  });
112246
- import { createHash as createHash33, randomUUID as randomUUID11 } from "crypto";
112348
+ import { createHash as createHash34, randomUUID as randomUUID11 } from "crypto";
112247
112349
  import { lstatSync as lstatSync32, mkdirSync as mkdirSync26, readFileSync as readFileSync40, realpathSync as realpathSync18, writeFileSync as writeFileSync25 } from "fs";
112248
112350
  import { basename as basename16, isAbsolute as isAbsolute27, join as join60 } from "path";
112249
112351
  import { createInterface } from "readline";
@@ -112284,7 +112386,7 @@ function registerRuntime(parent) {
112284
112386
  if (!expected)
112285
112387
  throw new Error("Cloud artifact not found");
112286
112388
  const bytes = await client2.download(id2, name);
112287
- if (bytes.length !== expected.byteSize || createHash33("sha256").update(bytes).digest("hex") !== expected.sha256)
112389
+ if (bytes.length !== expected.byteSize || createHash34("sha256").update(bytes).digest("hex") !== expected.sha256)
112288
112390
  throw new Error("Cloud artifact integrity verification failed");
112289
112391
  writeFileSync25(options.output, bytes, { flag: "wx", mode: 384 });
112290
112392
  console.log(JSON.stringify({ path: options.output, sha256: expected.sha256, byteSize: bytes.length }));
@@ -113938,7 +114040,7 @@ var init_portable_snapshot_filter = __esm(() => {
113938
114040
  });
113939
114041
 
113940
114042
  // src/lib/station-snapshot.ts
113941
- import { createHash as createHash34 } from "crypto";
114043
+ import { createHash as createHash35 } from "crypto";
113942
114044
  import {
113943
114045
  copyFileSync as copyFileSync2,
113944
114046
  mkdirSync as mkdirSync27,
@@ -113953,7 +114055,7 @@ function validateStationId(stationId) {
113953
114055
  }
113954
114056
  }
113955
114057
  function sha256File(filePath) {
113956
- return createHash34("sha256").update(readFileSync41(filePath)).digest("hex");
114058
+ return createHash35("sha256").update(readFileSync41(filePath)).digest("hex");
113957
114059
  }
113958
114060
  function scanHome(definition, homesRoot) {
113959
114061
  const homePath = homePathFor(definition, homesRoot);
@@ -114643,7 +114745,7 @@ var init_codex_hook_policy_recovery = __esm(() => {
114643
114745
 
114644
114746
  // src/lib/agent-codex-trust.ts
114645
114747
  import { lstatSync as lstatSync34, mkdirSync as mkdirSync28, readdirSync as readdirSync23, readFileSync as readFileSync42, realpathSync as realpathSync20, statSync as statSync22 } from "fs";
114646
- import { createHash as createHash35, randomUUID as randomUUID12 } from "crypto";
114748
+ import { createHash as createHash36, randomUUID as randomUUID12 } from "crypto";
114647
114749
  import { execFileSync as execFileSync2 } from "child_process";
114648
114750
  import { dirname as dirname36, isAbsolute as isAbsolute30, join as join64, resolve as resolve28 } from "path";
114649
114751
  import { homedir as homedir12 } from "os";
@@ -114653,11 +114755,11 @@ function verifyReleaseArtifact(proof, skillsCli) {
114653
114755
  const tarPath = realpathSync20(proof.packageTarPath);
114654
114756
  need5(statSync22(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
114655
114757
  const tarBytes = readFileSync42(tarPath);
114656
- need5(tarBytes.byteLength === proof.packageTarBytes && createHash35("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
114758
+ need5(tarBytes.byteLength === proof.packageTarBytes && createHash36("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
114657
114759
  const packageRoot = dirname36(dirname36(realpathSync20(skillsCli.receipt.path)));
114658
114760
  const manifest = readFileSync42(join64(packageRoot, "package.json"));
114659
- need5(createHash35("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
114660
- need5(createHash35("sha256").update(readFileSync42(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
114761
+ need5(createHash36("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
114762
+ need5(createHash36("sha256").update(readFileSync42(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
114661
114763
  const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync42(skillsCli.receipt.path)]];
114662
114764
  for (const [member, expected] of members2) {
114663
114765
  let actual;
@@ -114975,7 +115077,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
114975
115077
  }
114976
115078
  }
114977
115079
  var json2 = (value) => JSON.stringify(value, null, 2) + `
114978
- `, structure3 = (text4) => JSON.parse(JSON.stringify(Bun.TOML.parse(text4))), eventNames, makePlanDigest = (value) => createHash35("sha256").update(json2(value)).digest("hex"), safeNativeHook = (hook) => ({ key: hook.key, eventName: hook.eventName, handlerType: hook.handlerType, command: hook.command, matcher: hook.matcher, timeoutSec: hook.timeoutSec, async: hook.async, statusMessage: hook.statusMessage, additionalContextLimit: hook.additionalContextLimit, sourcePath: hook.sourcePath, source: hook.source, pluginId: hook.pluginId, isManaged: hook.isManaged, currentHash: hook.currentHash, enabled: hook.enabled, trustStatus: hook.trustStatus }), withoutCodexCommand = (value) => {
115080
+ `, structure3 = (text4) => JSON.parse(JSON.stringify(Bun.TOML.parse(text4))), eventNames, makePlanDigest = (value) => createHash36("sha256").update(json2(value)).digest("hex"), safeNativeHook = (hook) => ({ key: hook.key, eventName: hook.eventName, handlerType: hook.handlerType, command: hook.command, matcher: hook.matcher, timeoutSec: hook.timeoutSec, async: hook.async, statusMessage: hook.statusMessage, additionalContextLimit: hook.additionalContextLimit, sourcePath: hook.sourcePath, source: hook.source, pluginId: hook.pluginId, isManaged: hook.isManaged, currentHash: hook.currentHash, enabled: hook.enabled, trustStatus: hook.trustStatus }), withoutCodexCommand = (value) => {
114979
115081
  const copy = structuredClone(value);
114980
115082
  if (copy?.bridge?.commands && Object.hasOwn(copy.bridge.commands, "codex"))
114981
115083
  copy.bridge.commands.codex = "<reviewed-codex-binding>";
@@ -114999,7 +115101,7 @@ var init_agent_codex_trust = __esm(() => {
114999
115101
  });
115000
115102
 
115001
115103
  // src/lib/codex-native-trust.ts
115002
- import { createHash as createHash36 } from "crypto";
115104
+ import { createHash as createHash37 } from "crypto";
115003
115105
  import { readFileSync as readFileSync43 } from "fs";
115004
115106
  import { join as join65, resolve as resolve29 } from "path";
115005
115107
  function refuse5(detail) {
@@ -115072,7 +115174,7 @@ function applyCodexNativeTrust(plan, expectedPolicySha256) {
115072
115174
  receipt.readback = { policySha256: sha6(readback.text), digests, verified: true };
115073
115175
  return receipt;
115074
115176
  }
115075
- var CODEX_NATIVE_TRUST_PLAN_SCHEMA = "skills.codex-native-trust-plan/v1", CODEX_NATIVE_TRUST_RECEIPT_SCHEMA = "skills.codex-native-trust-receipt/v1", PLATFORM_KEY2, HEX_DIGEST2, MAX_DIGESTS = 16, sha6 = (data) => createHash36("sha256").update(data).digest("hex");
115177
+ var CODEX_NATIVE_TRUST_PLAN_SCHEMA = "skills.codex-native-trust-plan/v1", CODEX_NATIVE_TRUST_RECEIPT_SCHEMA = "skills.codex-native-trust-receipt/v1", PLATFORM_KEY2, HEX_DIGEST2, MAX_DIGESTS = 16, sha6 = (data) => createHash37("sha256").update(data).digest("hex");
115076
115178
  var init_codex_native_trust = __esm(() => {
115077
115179
  init_config();
115078
115180
  init_managed_policy();
@@ -115202,7 +115304,7 @@ __export(exports_agent_integration, {
115202
115304
  registerAgentIntegration: () => registerAgentIntegration
115203
115305
  });
115204
115306
  import { existsSync as existsSync36, lstatSync as lstatSync35, readFileSync as readFileSync44, readSync as readSync18, writeFileSync as writeFileSync27 } from "fs";
115205
- import { createHash as createHash37 } from "crypto";
115307
+ import { createHash as createHash38 } from "crypto";
115206
115308
  import { homedir as homedir13 } from "os";
115207
115309
  import { isAbsolute as isAbsolute31 } from "path";
115208
115310
  function pinnedHookProfile(input3, configuredProfile) {
@@ -115327,7 +115429,7 @@ function registerAgentIntegration(parent) {
115327
115429
  skillCount: catalog.skills.length,
115328
115430
  output: options.output,
115329
115431
  bytes: Buffer.byteLength(bytes),
115330
- sha256: createHash37("sha256").update(bytes).digest("hex")
115432
+ sha256: createHash38("sha256").update(bytes).digest("hex")
115331
115433
  };
115332
115434
  await writeCliOutput(options.json ? JSON.stringify(receipt) : `Captured ${receipt.skillCount} native Codex skill(s) in ${receipt.output}.`);
115333
115435
  } catch (error61) {
@@ -115336,16 +115438,16 @@ function registerAgentIntegration(parent) {
115336
115438
  process.exitCode = 1;
115337
115439
  }
115338
115440
  });
115339
- hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v4, codex-settings-v3, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
115340
- const capture2 = options.kind === "codex-settings-v4" ? captureCodexSettingsV4 : options.kind === "codex-settings-v3" ? captureCodexSettingsV3 : options.kind === "codex-settings-v2" ? captureCodexSettingsV2 : options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
115441
+ hook.command("witness").requiredOption("--kind <kind>", "sumi-settings-v1, claude-settings-v3, claude-settings-v2, codex-settings-v4, codex-settings-v3, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
115442
+ const capture2 = options.kind === "sumi-settings-v1" ? captureSumiSettings : options.kind === "codex-settings-v4" ? captureCodexSettingsV4 : options.kind === "codex-settings-v3" ? captureCodexSettingsV3 : options.kind === "codex-settings-v2" ? captureCodexSettingsV2 : options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
115341
115443
  if (!capture2)
115342
- throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v4, codex-settings-v3, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
115444
+ throw new Error("Unsupported witness kind; select sumi-settings-v1, claude-settings-v3, claude-settings-v2, codex-settings-v4, codex-settings-v3, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
115343
115445
  await writeCliOutput(JSON.stringify(capture2(options.path), null, 2));
115344
115446
  });
115345
- hook.command("rebind-settings").requiredOption("--agent <agent>", "claude or codex").requiredOption("--reviewed-preimage <path>", "Exact preserved legacy settings.json or config.toml").requiredOption("--expected-policy-sha256 <sha256>", "Exact current managed policy bytes").requiredOption("--expected-settings-sha256 <sha256>", "Exact current native settings bytes").option("--codex-witness-version <version>", "Explicit target: 2 (legacy default) 3 (service tier and model-advertised effort), or 4 (native availability UI counts)").option("--apply", "Apply the explicit semantic witness upgrade with preservation and readback", false).option("--json", "Return the metadata-only plan or receipt", false).description("Explicitly migrate a legacy native settings witness after proving only known preferences changed").action(async (options) => {
115447
+ hook.command("rebind-settings").requiredOption("--agent <agent>", "claude, codex or sumi").requiredOption("--reviewed-preimage <path>", "Exact preserved legacy settings.json, config.toml or sumi.json").requiredOption("--expected-policy-sha256 <sha256>", "Exact current managed policy bytes").requiredOption("--expected-settings-sha256 <sha256>", "Exact current native settings bytes").option("--codex-witness-version <version>", "Explicit target: 2 (legacy default) 3 (service tier and model-advertised effort), or 4 (native availability UI counts)").option("--apply", "Apply the explicit semantic witness upgrade with preservation and readback", false).option("--json", "Return the metadata-only plan or receipt", false).description("Explicitly migrate a legacy native settings witness after proving only known preferences changed").action(async (options) => {
115346
115448
  try {
115347
- if (!["claude", "codex"].includes(options.agent))
115348
- throw new Error("Settings witness rebind accepts claude or codex");
115449
+ if (!["claude", "codex", "sumi"].includes(options.agent))
115450
+ throw new Error("Settings witness rebind accepts claude, codex or sumi");
115349
115451
  if (options.codexWitnessVersion !== undefined && !["2", "3", "4"].includes(options.codexWitnessVersion))
115350
115452
  throw new Error("Codex witness version accepts 2, 3 or 4");
115351
115453
  const plan = planAgentSettingsWitnessUpgrade({ ...options.codexWitnessVersion !== undefined ? { targetCodexVersion: Number(options.codexWitnessVersion) } : {}, agent: options.agent, reviewedPreimage: options.reviewedPreimage, expectedPolicySha256: options.expectedPolicySha256, expectedSettingsSha256: options.expectedSettingsSha256 });
@@ -115573,6 +115675,7 @@ function registerAgentIntegration(parent) {
115573
115675
  }
115574
115676
  var RECOVERABLE_CONTEXT_CACHE_ERRORS;
115575
115677
  var init_agent_integration2 = __esm(() => {
115678
+ init_sumi_settings_witness();
115576
115679
  init_agent_hermes();
115577
115680
  init_context();
115578
115681
  init_agent_adapters();
@@ -115859,7 +115962,7 @@ var init_grants = __esm(() => {
115859
115962
  });
115860
115963
 
115861
115964
  // src/lib/station-hydrate.ts
115862
- import { createHash as createHash38 } from "crypto";
115965
+ import { createHash as createHash39 } from "crypto";
115863
115966
  import {
115864
115967
  copyFileSync as copyFileSync3,
115865
115968
  mkdirSync as mkdirSync29,
@@ -116062,7 +116165,7 @@ function skillSha256(skill) {
116062
116165
  return sha256File(skill.files[0].winner.fullPath);
116063
116166
  }
116064
116167
  const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
116065
- return createHash38("sha256").update(joined.sort().join(`
116168
+ return createHash39("sha256").update(joined.sort().join(`
116066
116169
  `)).digest("hex");
116067
116170
  }
116068
116171
  function writeStationHydration(options) {
@@ -116219,7 +116322,7 @@ var init_hydrate = __esm(() => {
116219
116322
  });
116220
116323
 
116221
116324
  // src/lib/prepare-skill.ts
116222
- import { createHash as createHash39, randomUUID as randomUUID13 } from "crypto";
116325
+ import { createHash as createHash40, randomUUID as randomUUID13 } from "crypto";
116223
116326
  import { chmodSync as chmodSync5, existsSync as existsSync37, lstatSync as lstatSync36, mkdirSync as mkdirSync30, mkdtempSync as mkdtempSync6, readFileSync as readFileSync46, readdirSync as readdirSync25, renameSync as renameSync15, rmSync as rmSync9, writeFileSync as writeFileSync31 } from "fs";
116224
116327
  import { tmpdir as tmpdir2 } from "os";
116225
116328
  import { dirname as dirname38, isAbsolute as isAbsolute32, join as join67, relative as relative12, resolve as resolve31, sep as sep15 } from "path";
@@ -116418,7 +116521,7 @@ function snapshot2(root2) {
116418
116521
  if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
116419
116522
  throw new Error("Skill root must be a real directory, not a symlink.");
116420
116523
  const files = [], directories = [];
116421
- const hash6 = createHash39("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
116524
+ const hash6 = createHash40("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
116422
116525
  let count = 0, bytes = 0;
116423
116526
  const walk2 = (relative13) => {
116424
116527
  for (const name of readdirSync25(join67(root2, relative13)).sort()) {