@hasna/skills 0.10.48 → 0.10.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -1
- package/bin/index.js +1137 -667
- package/bin/maintenance.js +18 -0
- package/bin/mcp.js +88 -11
- package/bin/migrate.js +19 -1
- package/bin/server.js +19 -1
- package/bin/worker.js +19 -1
- package/dist/cli/commands/runtime-launcher.d.ts +102 -0
- package/dist/cli/commands/runtime.d.ts +7 -0
- package/dist/cli/index.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +452 -272
- package/dist/lib/agent-discovery.d.ts +1 -1
- package/dist/lib/agent-integration.d.ts +1 -0
- package/dist/lib/claude-settings-witness.d.ts +19 -0
- package/dist/lib/launch-cwd-apply.d.ts +1 -0
- package/dist/lib/launch-cwd.d.ts +5 -0
- package/dist/lib/self-spawn.d.ts +21 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/sdk/index.js +433 -255
- package/dist/server/index.d.ts +1 -1
- package/dist/server/maintenance.d.ts +1 -1
- package/dist/server/migrate.d.ts +17 -0
- package/dist/server/worker.d.ts +1 -0
- package/docs/plugin-admission.md +39 -2
- package/package.json +1 -1
package/bin/maintenance.js
CHANGED
|
@@ -1872,6 +1872,24 @@ var require_commander = __commonJS((exports) => {
|
|
|
1872
1872
|
exports.InvalidOptionArgumentError = InvalidArgumentError;
|
|
1873
1873
|
});
|
|
1874
1874
|
|
|
1875
|
+
// src/lib/launch-cwd.ts
|
|
1876
|
+
var LAUNCH_CWD_VARIABLE = "HASNA_SKILLS_LAUNCH_CWD";
|
|
1877
|
+
function restoreLaunchCwd(env = process.env) {
|
|
1878
|
+
const requested = env[LAUNCH_CWD_VARIABLE];
|
|
1879
|
+
delete env[LAUNCH_CWD_VARIABLE];
|
|
1880
|
+
if (!requested || !requested.startsWith("/"))
|
|
1881
|
+
return { restored: false, cwd: process.cwd() };
|
|
1882
|
+
try {
|
|
1883
|
+
process.chdir(requested);
|
|
1884
|
+
return { restored: true, cwd: process.cwd() };
|
|
1885
|
+
} catch {
|
|
1886
|
+
return { restored: false, cwd: process.cwd() };
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
// src/lib/launch-cwd-apply.ts
|
|
1891
|
+
restoreLaunchCwd();
|
|
1892
|
+
|
|
1875
1893
|
// node_modules/commander/esm.mjs
|
|
1876
1894
|
var import__ = __toESM(require_commander(), 1);
|
|
1877
1895
|
var {
|
package/bin/mcp.js
CHANGED
|
@@ -20019,7 +20019,7 @@ var package_default;
|
|
|
20019
20019
|
var init_package = __esm(() => {
|
|
20020
20020
|
package_default = {
|
|
20021
20021
|
name: "@hasna/skills",
|
|
20022
|
-
version: "0.10.
|
|
20022
|
+
version: "0.10.50",
|
|
20023
20023
|
description: "Skills library for AI coding agents",
|
|
20024
20024
|
type: "module",
|
|
20025
20025
|
bin: {
|
|
@@ -38370,7 +38370,9 @@ function inferencePreference(key, child, version2) {
|
|
|
38370
38370
|
function settingsDigest(text, version2 = 1) {
|
|
38371
38371
|
const value = parse6(text);
|
|
38372
38372
|
value.entries = value.entries.filter(([key, child]) => {
|
|
38373
|
-
if (version2
|
|
38373
|
+
if (version2 === 4 && key === "theme" && child.kind === "string" && BUILTIN_THEMES.has(child.value))
|
|
38374
|
+
return false;
|
|
38375
|
+
if (version2 !== 1 && inferencePreference(key, child, version2 === 4 ? 3 : version2))
|
|
38374
38376
|
return false;
|
|
38375
38377
|
if (key === "model") {
|
|
38376
38378
|
need(child.kind === "string", "contains an invalid model selection");
|
|
@@ -38418,6 +38420,16 @@ function hashClaudeSettingsReplacementV3(text, budget) {
|
|
|
38418
38420
|
budget.remaining -= bytes;
|
|
38419
38421
|
return settingsDigest(text, 3);
|
|
38420
38422
|
}
|
|
38423
|
+
function captureClaudeSettingsV4(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
38424
|
+
return { path, hashMode: "claude-settings-v4", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 4) };
|
|
38425
|
+
}
|
|
38426
|
+
function hashClaudeSettingsReplacementV4(text, budget) {
|
|
38427
|
+
need(typeof text === "string", "requires settings text");
|
|
38428
|
+
const bytes = Buffer.byteLength(text);
|
|
38429
|
+
need(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
38430
|
+
budget.remaining -= bytes;
|
|
38431
|
+
return settingsDigest(text, 4);
|
|
38432
|
+
}
|
|
38421
38433
|
function hashNativeJsonControls(text, excludedMetadata) {
|
|
38422
38434
|
need(Buffer.byteLength(text) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
|
|
38423
38435
|
const value = parse6(text);
|
|
@@ -38450,7 +38462,7 @@ function hashSumiNativeJsonControls(text) {
|
|
|
38450
38462
|
});
|
|
38451
38463
|
return createHash2("sha256").update("hasna.skills.sumi-settings.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
38452
38464
|
}
|
|
38453
|
-
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;
|
|
38465
|
+
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, CLAUDE_BUILTIN_THEMES, BUILTIN_THEMES, PERSISTED_EFFORT_LEVELS;
|
|
38454
38466
|
var init_claude_settings_witness = __esm(() => {
|
|
38455
38467
|
CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
38456
38468
|
BOOLEAN_PREFERENCES = new Set([
|
|
@@ -38504,6 +38516,8 @@ var init_claude_settings_witness = __esm(() => {
|
|
|
38504
38516
|
"claude-opus-4-6[1m]",
|
|
38505
38517
|
"claude-sonnet-4-6[1m]"
|
|
38506
38518
|
]);
|
|
38519
|
+
CLAUDE_BUILTIN_THEMES = Object.freeze(["auto", "dark", "light", "dark-daltonized", "light-daltonized", "dark-ansi", "light-ansi"]);
|
|
38520
|
+
BUILTIN_THEMES = new Set(CLAUDE_BUILTIN_THEMES);
|
|
38507
38521
|
PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
|
|
38508
38522
|
});
|
|
38509
38523
|
|
|
@@ -38666,14 +38680,14 @@ function assertAgentPolicyCollections(policy) {
|
|
|
38666
38680
|
text(source.path);
|
|
38667
38681
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
38668
38682
|
if (source.hashMode !== undefined)
|
|
38669
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "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));
|
|
38683
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-settings-v4", "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));
|
|
38670
38684
|
if (source.hashMode === "claude-plugin-manifest-v1")
|
|
38671
38685
|
requireBound(agent === "claude" && value.agent === "claude" && ["automatic", "reviewed"].includes(value.method) && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute4(source.path) && resolve3(source.path) === source.path && source.path.endsWith(join10(sep3, ".claude-plugin", "plugin.json")) && source.managedPlugins === undefined);
|
|
38672
38686
|
if (source.hashMode === "sumi-settings-v1")
|
|
38673
38687
|
requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute4(source.path) && resolve3(source.path) === source.path && basename4(source.path) === "sumi.json");
|
|
38674
38688
|
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
|
|
38675
38689
|
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute4(source.path) && resolve3(source.path) === source.path && basename4(source.path) === "config.toml");
|
|
38676
|
-
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
|
|
38690
|
+
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4"))
|
|
38677
38691
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute4(source.path) && resolve3(source.path) === source.path && basename4(source.path) === "settings.json");
|
|
38678
38692
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2")
|
|
38679
38693
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute4(source.path) && resolve3(source.path) === source.path && basename4(source.path) === "known_marketplaces.json");
|
|
@@ -48869,6 +48883,50 @@ function unchanged2(before) {
|
|
|
48869
48883
|
var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
|
|
48870
48884
|
var init_codex_hook_trust_files = () => {};
|
|
48871
48885
|
|
|
48886
|
+
// src/cli/commands/runtime-launcher.ts
|
|
48887
|
+
var PINNED_LAUNCHER_BUN_FLAGS, PINNED_LAUNCHER_ENV_NAMES, PINNED_LAUNCHER_ENV_PREFIXES, ENV_PREFIX, ENV_EXACT, COMMAND_LINE, PINNED_LAUNCHER_MAX_BYTES;
|
|
48888
|
+
var init_runtime_launcher = __esm(() => {
|
|
48889
|
+
PINNED_LAUNCHER_BUN_FLAGS = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install"];
|
|
48890
|
+
PINNED_LAUNCHER_ENV_NAMES = [
|
|
48891
|
+
"HOME",
|
|
48892
|
+
"PATH",
|
|
48893
|
+
"TMPDIR",
|
|
48894
|
+
"TERM",
|
|
48895
|
+
"TERM_PROGRAM",
|
|
48896
|
+
"TERM_PROGRAM_VERSION",
|
|
48897
|
+
"COLORTERM",
|
|
48898
|
+
"LANG",
|
|
48899
|
+
"USER",
|
|
48900
|
+
"LOGNAME",
|
|
48901
|
+
"SHELL",
|
|
48902
|
+
"TZ",
|
|
48903
|
+
"NO_COLOR",
|
|
48904
|
+
"FORCE_COLOR",
|
|
48905
|
+
"CI",
|
|
48906
|
+
"COLUMNS",
|
|
48907
|
+
"LINES",
|
|
48908
|
+
"EDITOR",
|
|
48909
|
+
"VISUAL",
|
|
48910
|
+
"PAGER",
|
|
48911
|
+
"SSH_AUTH_SOCK",
|
|
48912
|
+
"DATABASE_URL",
|
|
48913
|
+
"TERMINAL_CWD",
|
|
48914
|
+
"CODEX_HOME",
|
|
48915
|
+
"HERMES_HOME",
|
|
48916
|
+
"HERMES_ENABLE_PROJECT_PLUGINS",
|
|
48917
|
+
"HOST",
|
|
48918
|
+
"PORT",
|
|
48919
|
+
"NODE_ENV",
|
|
48920
|
+
"AGENT_ID",
|
|
48921
|
+
"ECS_CONTAINER_METADATA_URI_V4"
|
|
48922
|
+
];
|
|
48923
|
+
PINNED_LAUNCHER_ENV_PREFIXES = ["HASNA", "SKILLS", "SKILL", "MCP", "XDG", "LC", "AWS"];
|
|
48924
|
+
ENV_PREFIX = new RegExp(`^(${PINNED_LAUNCHER_ENV_PREFIXES.join("|")})_`);
|
|
48925
|
+
ENV_EXACT = new Set(PINNED_LAUNCHER_ENV_NAMES);
|
|
48926
|
+
COMMAND_LINE = new RegExp(`^set -- '([^']+)' ${PINNED_LAUNCHER_BUN_FLAGS.join(" ")} '--cwd=([^']+)' '([^']+)' "\\$@"$`, "m");
|
|
48927
|
+
PINNED_LAUNCHER_MAX_BYTES = 16 * 1024;
|
|
48928
|
+
});
|
|
48929
|
+
|
|
48872
48930
|
// src/lib/agent-integration.ts
|
|
48873
48931
|
var init_agent_integration = __esm(() => {
|
|
48874
48932
|
init_sumi_settings_witness();
|
|
@@ -48889,6 +48947,7 @@ var init_agent_integration = __esm(() => {
|
|
|
48889
48947
|
init_agent_hermes();
|
|
48890
48948
|
init_claude_settings_witness();
|
|
48891
48949
|
init_codex_hook_trust_files();
|
|
48950
|
+
init_runtime_launcher();
|
|
48892
48951
|
});
|
|
48893
48952
|
|
|
48894
48953
|
// src/lib/home-migration.ts
|
|
@@ -50535,13 +50594,13 @@ function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
|
50535
50594
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
50536
50595
|
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;
|
|
50537
50596
|
}
|
|
50538
|
-
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
|
|
50597
|
+
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) {
|
|
50539
50598
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
50540
50599
|
throw new Error("Claude settings witnesses require exact typed metadata");
|
|
50541
|
-
const current = (source.hashMode === "claude-settings-v3" ? captureClaudeSettingsV3 : source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget2).sha256;
|
|
50600
|
+
const current = (source.hashMode === "claude-settings-v4" ? captureClaudeSettingsV4 : source.hashMode === "claude-settings-v3" ? captureClaudeSettingsV3 : source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget2).sha256;
|
|
50542
50601
|
if (current !== source.sha256)
|
|
50543
50602
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
50544
|
-
return changes?.has(source.path) ? (source.hashMode === "claude-settings-v3" ? hashClaudeSettingsReplacementV3 : source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
50603
|
+
return changes?.has(source.path) ? (source.hashMode === "claude-settings-v4" ? hashClaudeSettingsReplacementV4 : source.hashMode === "claude-settings-v3" ? hashClaudeSettingsReplacementV3 : source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
50545
50604
|
}
|
|
50546
50605
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") {
|
|
50547
50606
|
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))
|
|
@@ -50760,7 +50819,7 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
50760
50819
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
50761
50820
|
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" || basename8(source.path) !== "config.toml"))
|
|
50762
50821
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
50763
|
-
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
|
|
50822
|
+
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
|
|
50764
50823
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
50765
50824
|
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
50766
50825
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
@@ -50882,7 +50941,7 @@ function resolveAgentDiscovery(options) {
|
|
|
50882
50941
|
verifyAgentDiscovery(retained);
|
|
50883
50942
|
if (!retained.sources.some((source) => source.path === canonical7(configPath) && source.format === undefined && source.fields === undefined))
|
|
50884
50943
|
unresolved("retained review is missing the full agent configuration source");
|
|
50885
|
-
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 !== canonical7(configPath)))
|
|
50944
|
+
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 === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
50886
50945
|
unresolved("retained settings witness names another configuration source");
|
|
50887
50946
|
const covered = supersedesSettingsProjection(agent, retained.sources, canonical7(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical7(configPath), source)) : sources;
|
|
50888
50947
|
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual4(saved, source))) || [...roots].some((root) => !retained.roots.includes(root)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
@@ -50896,7 +50955,7 @@ function resolveAgentDiscovery(options) {
|
|
|
50896
50955
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
50897
50956
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
50898
50957
|
verifyAgentDiscovery(supplied);
|
|
50899
|
-
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 !== canonical7(configPath)))
|
|
50958
|
+
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 === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
50900
50959
|
throw new Error("Semantic settings witnesses must name the configured agent configuration source");
|
|
50901
50960
|
if (!review.sources.some((source) => source.path === canonical7(configPath)))
|
|
50902
50961
|
throw new Error("Discovery review must include the agent configuration source");
|
|
@@ -63996,6 +64055,24 @@ var init_http = __esm(() => {
|
|
|
63996
64055
|
init_server3();
|
|
63997
64056
|
});
|
|
63998
64057
|
|
|
64058
|
+
// src/lib/launch-cwd.ts
|
|
64059
|
+
var LAUNCH_CWD_VARIABLE = "HASNA_SKILLS_LAUNCH_CWD";
|
|
64060
|
+
function restoreLaunchCwd(env = process.env) {
|
|
64061
|
+
const requested = env[LAUNCH_CWD_VARIABLE];
|
|
64062
|
+
delete env[LAUNCH_CWD_VARIABLE];
|
|
64063
|
+
if (!requested || !requested.startsWith("/"))
|
|
64064
|
+
return { restored: false, cwd: process.cwd() };
|
|
64065
|
+
try {
|
|
64066
|
+
process.chdir(requested);
|
|
64067
|
+
return { restored: true, cwd: process.cwd() };
|
|
64068
|
+
} catch {
|
|
64069
|
+
return { restored: false, cwd: process.cwd() };
|
|
64070
|
+
}
|
|
64071
|
+
}
|
|
64072
|
+
|
|
64073
|
+
// src/lib/launch-cwd-apply.ts
|
|
64074
|
+
restoreLaunchCwd();
|
|
64075
|
+
|
|
63999
64076
|
// src/mcp/index.ts
|
|
64000
64077
|
init_stdio2();
|
|
64001
64078
|
init_package();
|
package/bin/migrate.js
CHANGED
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
|
+
// src/lib/launch-cwd.ts
|
|
5
|
+
var LAUNCH_CWD_VARIABLE = "HASNA_SKILLS_LAUNCH_CWD";
|
|
6
|
+
function restoreLaunchCwd(env = process.env) {
|
|
7
|
+
const requested = env[LAUNCH_CWD_VARIABLE];
|
|
8
|
+
delete env[LAUNCH_CWD_VARIABLE];
|
|
9
|
+
if (!requested || !requested.startsWith("/"))
|
|
10
|
+
return { restored: false, cwd: process.cwd() };
|
|
11
|
+
try {
|
|
12
|
+
process.chdir(requested);
|
|
13
|
+
return { restored: true, cwd: process.cwd() };
|
|
14
|
+
} catch {
|
|
15
|
+
return { restored: false, cwd: process.cwd() };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/lib/launch-cwd-apply.ts
|
|
20
|
+
restoreLaunchCwd();
|
|
21
|
+
|
|
4
22
|
// src/server/migrate.ts
|
|
5
23
|
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
|
|
6
24
|
import { join as join5 } from "path";
|
|
7
25
|
// package.json
|
|
8
26
|
var package_default = {
|
|
9
27
|
name: "@hasna/skills",
|
|
10
|
-
version: "0.10.
|
|
28
|
+
version: "0.10.50",
|
|
11
29
|
description: "Skills library for AI coding agents",
|
|
12
30
|
type: "module",
|
|
13
31
|
bin: {
|
package/bin/server.js
CHANGED
|
@@ -24119,10 +24119,28 @@ __export(exports_dist_es8, {
|
|
|
24119
24119
|
var init_dist_es9 = __esm(() => {
|
|
24120
24120
|
init_fromIni();
|
|
24121
24121
|
});
|
|
24122
|
+
|
|
24123
|
+
// src/lib/launch-cwd.ts
|
|
24124
|
+
var LAUNCH_CWD_VARIABLE = "HASNA_SKILLS_LAUNCH_CWD";
|
|
24125
|
+
function restoreLaunchCwd(env = process.env) {
|
|
24126
|
+
const requested = env[LAUNCH_CWD_VARIABLE];
|
|
24127
|
+
delete env[LAUNCH_CWD_VARIABLE];
|
|
24128
|
+
if (!requested || !requested.startsWith("/"))
|
|
24129
|
+
return { restored: false, cwd: process.cwd() };
|
|
24130
|
+
try {
|
|
24131
|
+
process.chdir(requested);
|
|
24132
|
+
return { restored: true, cwd: process.cwd() };
|
|
24133
|
+
} catch {
|
|
24134
|
+
return { restored: false, cwd: process.cwd() };
|
|
24135
|
+
}
|
|
24136
|
+
}
|
|
24137
|
+
|
|
24138
|
+
// src/lib/launch-cwd-apply.ts
|
|
24139
|
+
restoreLaunchCwd();
|
|
24122
24140
|
// package.json
|
|
24123
24141
|
var package_default = {
|
|
24124
24142
|
name: "@hasna/skills",
|
|
24125
|
-
version: "0.10.
|
|
24143
|
+
version: "0.10.50",
|
|
24126
24144
|
description: "Skills library for AI coding agents",
|
|
24127
24145
|
type: "module",
|
|
24128
24146
|
bin: {
|
package/bin/worker.js
CHANGED
|
@@ -24120,12 +24120,30 @@ var init_dist_es9 = __esm(() => {
|
|
|
24120
24120
|
init_fromIni();
|
|
24121
24121
|
});
|
|
24122
24122
|
|
|
24123
|
+
// src/lib/launch-cwd.ts
|
|
24124
|
+
var LAUNCH_CWD_VARIABLE = "HASNA_SKILLS_LAUNCH_CWD";
|
|
24125
|
+
function restoreLaunchCwd(env = process.env) {
|
|
24126
|
+
const requested = env[LAUNCH_CWD_VARIABLE];
|
|
24127
|
+
delete env[LAUNCH_CWD_VARIABLE];
|
|
24128
|
+
if (!requested || !requested.startsWith("/"))
|
|
24129
|
+
return { restored: false, cwd: process.cwd() };
|
|
24130
|
+
try {
|
|
24131
|
+
process.chdir(requested);
|
|
24132
|
+
return { restored: true, cwd: process.cwd() };
|
|
24133
|
+
} catch {
|
|
24134
|
+
return { restored: false, cwd: process.cwd() };
|
|
24135
|
+
}
|
|
24136
|
+
}
|
|
24137
|
+
|
|
24138
|
+
// src/lib/launch-cwd-apply.ts
|
|
24139
|
+
restoreLaunchCwd();
|
|
24140
|
+
|
|
24123
24141
|
// src/server/worker.ts
|
|
24124
24142
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
24125
24143
|
// package.json
|
|
24126
24144
|
var package_default = {
|
|
24127
24145
|
name: "@hasna/skills",
|
|
24128
|
-
version: "0.10.
|
|
24146
|
+
version: "0.10.50",
|
|
24129
24147
|
description: "Skills library for AI coding agents",
|
|
24130
24148
|
type: "module",
|
|
24131
24149
|
bin: {
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export declare const PINNED_LAUNCHER_SCHEMA = "hasna-skills-pinned-launcher-v1";
|
|
2
|
+
/** The variable the launcher uses to hand the caller's directory to the CLI. */
|
|
3
|
+
export declare const LAUNCH_CWD_VARIABLE = "HASNA_SKILLS_LAUNCH_CWD";
|
|
4
|
+
/** Bun runtime flags that remove every working-directory configuration source. */
|
|
5
|
+
export declare const PINNED_LAUNCHER_BUN_FLAGS: readonly ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install"];
|
|
6
|
+
/**
|
|
7
|
+
* Environment names passed through `env -i`, by exact name. Everything else,
|
|
8
|
+
* including `BUN_*`, `NODE_OPTIONS`, `DYLD_*`, `LD_*` and proxy settings, is
|
|
9
|
+
* dropped. The handling is total on purpose: a name is either listed here,
|
|
10
|
+
* matches a prefix below, or never reaches the runtime.
|
|
11
|
+
*/
|
|
12
|
+
export declare const PINNED_LAUNCHER_ENV_NAMES: readonly ["HOME", "PATH", "TMPDIR", "TERM", "TERM_PROGRAM", "TERM_PROGRAM_VERSION", "COLORTERM", "LANG", "USER", "LOGNAME", "SHELL", "TZ", "NO_COLOR", "FORCE_COLOR", "CI", "COLUMNS", "LINES", "EDITOR", "VISUAL", "PAGER", "SSH_AUTH_SOCK", "DATABASE_URL", "TERMINAL_CWD", "CODEX_HOME", "HERMES_HOME", "HERMES_ENABLE_PROJECT_PLUGINS", "HOST", "PORT", "NODE_ENV", "AGENT_ID", "ECS_CONTAINER_METADATA_URI_V4"];
|
|
13
|
+
/** Environment name prefixes passed through, for the app's own documented overrides. */
|
|
14
|
+
export declare const PINNED_LAUNCHER_ENV_PREFIXES: readonly ["HASNA", "SKILLS", "SKILL", "MCP", "XDG", "LC", "AWS"];
|
|
15
|
+
/** The allowlisted subset of an environment, by the same rule the launcher applies. */
|
|
16
|
+
export declare function pinnedLauncherEnvironment(env: Record<string, string | undefined>): Record<string, string>;
|
|
17
|
+
export type LauncherShape = "symlink" | "pinned";
|
|
18
|
+
export interface PinnedLauncherBinding {
|
|
19
|
+
runtime: string;
|
|
20
|
+
cwd: string;
|
|
21
|
+
entry: string;
|
|
22
|
+
}
|
|
23
|
+
export type LauncherState = {
|
|
24
|
+
shape: "symlink";
|
|
25
|
+
linkTarget: string;
|
|
26
|
+
target: string;
|
|
27
|
+
} | {
|
|
28
|
+
shape: "pinned";
|
|
29
|
+
runtime: string;
|
|
30
|
+
cwd: string;
|
|
31
|
+
target: string;
|
|
32
|
+
sha256: string;
|
|
33
|
+
};
|
|
34
|
+
export type InspectedLauncher = {
|
|
35
|
+
kind: "symlink";
|
|
36
|
+
linkTarget: string;
|
|
37
|
+
target: string;
|
|
38
|
+
} | {
|
|
39
|
+
kind: "pinned";
|
|
40
|
+
runtime: string;
|
|
41
|
+
cwd: string;
|
|
42
|
+
target: string;
|
|
43
|
+
sha256: string;
|
|
44
|
+
text: string;
|
|
45
|
+
} | {
|
|
46
|
+
kind: "foreign";
|
|
47
|
+
};
|
|
48
|
+
/** The exact launcher text for one Bun binary, trusted directory and entry. Deterministic. */
|
|
49
|
+
export declare function renderPinnedLauncher(binding: PinnedLauncherBinding): string;
|
|
50
|
+
/** Parse launcher text; only the exact rendered shape is accepted. */
|
|
51
|
+
export declare function parsePinnedLauncher(text: string): PinnedLauncherBinding | null;
|
|
52
|
+
/**
|
|
53
|
+
* Resolve a command path the way the symlink checks used to: the physical file
|
|
54
|
+
* it reaches and, when that file is a managed pinned launcher (its exact
|
|
55
|
+
* rendered text), the entry the launcher runs. `entry` equals `physical` for a
|
|
56
|
+
* symlink or a plain executable. A pinned entry must itself be a physical path.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveLauncherCommand(path: string): {
|
|
59
|
+
physical: string;
|
|
60
|
+
entry: string;
|
|
61
|
+
pinned: (PinnedLauncherBinding & {
|
|
62
|
+
sha256: string;
|
|
63
|
+
}) | null;
|
|
64
|
+
};
|
|
65
|
+
/** Classify the launcher at `path` without following anything but its own symlink. */
|
|
66
|
+
export declare function inspectLauncher(path: string): InspectedLauncher;
|
|
67
|
+
/** The entry a managed launcher runs, whichever shape it has. */
|
|
68
|
+
export declare function launcherTarget(path: string): string;
|
|
69
|
+
/** The "link text" of a managed launcher: the symlink text, or the pinned entry path. */
|
|
70
|
+
export declare function launcherLinkText(path: string): string;
|
|
71
|
+
/** Whether the launcher at `path` is exactly `state`: same shape, text and target. */
|
|
72
|
+
export declare function launcherIs(path: string, state: LauncherState): boolean;
|
|
73
|
+
/** The pinned launcher text for a state, verified against the recorded digest. */
|
|
74
|
+
export declare function pinnedLauncherText(state: {
|
|
75
|
+
runtime: string;
|
|
76
|
+
cwd: string;
|
|
77
|
+
target: string;
|
|
78
|
+
sha256: string;
|
|
79
|
+
}): string;
|
|
80
|
+
/** Build the pinned state for an entry under the given Bun binary and trusted directory. */
|
|
81
|
+
export declare function pinnedLauncherState(runtime: string, cwd: string, target: string): Extract<LauncherState, {
|
|
82
|
+
shape: "pinned";
|
|
83
|
+
}>;
|
|
84
|
+
/**
|
|
85
|
+
* Create a launcher in `state` at a path that must not exist yet, and read it
|
|
86
|
+
* back. Symlinks are created as-is; pinned launchers are regular 0755 files.
|
|
87
|
+
*/
|
|
88
|
+
export declare function materializeLauncher(path: string, state: LauncherState): void;
|
|
89
|
+
/**
|
|
90
|
+
* The Bun binary launchers are pinned to: the exact runtime running the
|
|
91
|
+
* updater, resolved physically and required to be owned by root or the
|
|
92
|
+
* current user, executable, and not writable by group or others.
|
|
93
|
+
*/
|
|
94
|
+
export declare function pinnedLauncherRuntime(): string;
|
|
95
|
+
/** A pinned runtime is a physical, executable regular file owned by root or the current user and not group/world-writable. */
|
|
96
|
+
export declare function assertPinnedLauncherRuntimeSafe(runtime: string): void;
|
|
97
|
+
/**
|
|
98
|
+
* The launcher depends on `/bin/sh -p`, `/usr/bin/awk` and `/usr/bin/env`.
|
|
99
|
+
* Refuse before any launcher is written when this station's shell rejects
|
|
100
|
+
* `-p` (for example dash before 0.5.11), so no launcher is left unusable.
|
|
101
|
+
*/
|
|
102
|
+
export declare function assertPinnedLauncherShell(): void;
|
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
export declare function registerRuntime(parent: Command): void;
|
|
3
|
+
/**
|
|
4
|
+
* The command to run for the Skills selected on PATH, after checking that it
|
|
5
|
+
* runs the installed entry. A symlink is compared by its physical target, as
|
|
6
|
+
* before; a managed pinned launcher by the exact entry it runs, and it is run
|
|
7
|
+
* through the launcher so the caller's directory configures nothing.
|
|
8
|
+
*/
|
|
9
|
+
export declare function selectedSkillsCommand(selected: string, installed: string): string;
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
|
|
2
|
+
import "../lib/launch-cwd-apply.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -64,7 +64,7 @@ export { planAgentIntegration, planClaudeStopHookUpdate, planClaudePreToolUseHoo
|
|
|
64
64
|
export type { ClaudeManagedHookProjection, ClaudeManagedHookProjectionOptions } from "./lib/agent-integration.js";
|
|
65
65
|
export { captureDiscoveryDirectories, captureDiscoveryByteSources, captureDiscoveryPathSources, type DiscoveryDirectory, type DiscoverySource } from "./lib/agent-discovery.js";
|
|
66
66
|
export { captureClaudeMarketplaceRegistry, captureClaudeMarketplaceRegistryV2 } from "./lib/claude-marketplace-registry.js";
|
|
67
|
-
export { captureClaudeSettings, captureClaudeSettingsV2, captureClaudeSettingsV3, upgradeClaudeSettingsWitness } from "./lib/claude-settings-witness.js";
|
|
67
|
+
export { captureClaudeSettings, captureClaudeSettingsV2, captureClaudeSettingsV3, captureClaudeSettingsV4, upgradeClaudeSettingsWitness, upgradeClaudeSettingsWitnessV4 } from "./lib/claude-settings-witness.js";
|
|
68
68
|
export { buildPluginProjection, pluginTreeDigest, type PluginProjectionManifest, type PluginPayloadMapping, type PluginFileWitness } from "./lib/plugin-projection.js";
|
|
69
69
|
export { planPluginAdmission, admitPlugin, resolveAdmittedPlugin, pluginResolverCommand, type PluginAdmissionTarget, type PluginAdmissionBinding, type PluginAdmissionPrincipal, type PluginAdmissionPlan, type PluginAdmissionIdentity, type PluginBundleIdentity, type PluginRoutingIdentity, type PluginAdmissionReceipt } from "./lib/plugin-admission.js";
|
|
70
70
|
export { captureManagedPluginRegistry, type ManagedPluginRegistrationWitness } from "./lib/plugin-discovery.js";
|