@hasna/skills 0.10.47 → 0.10.49

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.
@@ -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.47",
20022
+ version: "0.10.49",
20023
20023
  description: "Skills library for AI coding agents",
20024
20024
  type: "module",
20025
20025
  bin: {
@@ -48869,6 +48869,50 @@ function unchanged2(before) {
48869
48869
  var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
48870
48870
  var init_codex_hook_trust_files = () => {};
48871
48871
 
48872
+ // src/cli/commands/runtime-launcher.ts
48873
+ var PINNED_LAUNCHER_BUN_FLAGS, PINNED_LAUNCHER_ENV_NAMES, PINNED_LAUNCHER_ENV_PREFIXES, ENV_PREFIX, ENV_EXACT, COMMAND_LINE, PINNED_LAUNCHER_MAX_BYTES;
48874
+ var init_runtime_launcher = __esm(() => {
48875
+ PINNED_LAUNCHER_BUN_FLAGS = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install"];
48876
+ PINNED_LAUNCHER_ENV_NAMES = [
48877
+ "HOME",
48878
+ "PATH",
48879
+ "TMPDIR",
48880
+ "TERM",
48881
+ "TERM_PROGRAM",
48882
+ "TERM_PROGRAM_VERSION",
48883
+ "COLORTERM",
48884
+ "LANG",
48885
+ "USER",
48886
+ "LOGNAME",
48887
+ "SHELL",
48888
+ "TZ",
48889
+ "NO_COLOR",
48890
+ "FORCE_COLOR",
48891
+ "CI",
48892
+ "COLUMNS",
48893
+ "LINES",
48894
+ "EDITOR",
48895
+ "VISUAL",
48896
+ "PAGER",
48897
+ "SSH_AUTH_SOCK",
48898
+ "DATABASE_URL",
48899
+ "TERMINAL_CWD",
48900
+ "CODEX_HOME",
48901
+ "HERMES_HOME",
48902
+ "HERMES_ENABLE_PROJECT_PLUGINS",
48903
+ "HOST",
48904
+ "PORT",
48905
+ "NODE_ENV",
48906
+ "AGENT_ID",
48907
+ "ECS_CONTAINER_METADATA_URI_V4"
48908
+ ];
48909
+ PINNED_LAUNCHER_ENV_PREFIXES = ["HASNA", "SKILLS", "SKILL", "MCP", "XDG", "LC", "AWS"];
48910
+ ENV_PREFIX = new RegExp(`^(${PINNED_LAUNCHER_ENV_PREFIXES.join("|")})_`);
48911
+ ENV_EXACT = new Set(PINNED_LAUNCHER_ENV_NAMES);
48912
+ COMMAND_LINE = new RegExp(`^set -- '([^']+)' ${PINNED_LAUNCHER_BUN_FLAGS.join(" ")} '--cwd=([^']+)' '([^']+)' "\\$@"$`, "m");
48913
+ PINNED_LAUNCHER_MAX_BYTES = 16 * 1024;
48914
+ });
48915
+
48872
48916
  // src/lib/agent-integration.ts
48873
48917
  var init_agent_integration = __esm(() => {
48874
48918
  init_sumi_settings_witness();
@@ -48889,6 +48933,7 @@ var init_agent_integration = __esm(() => {
48889
48933
  init_agent_hermes();
48890
48934
  init_claude_settings_witness();
48891
48935
  init_codex_hook_trust_files();
48936
+ init_runtime_launcher();
48892
48937
  });
48893
48938
 
48894
48939
  // src/lib/home-migration.ts
@@ -50902,7 +50947,7 @@ function resolveAgentDiscovery(options) {
50902
50947
  throw new Error("Discovery review must include the agent configuration source");
50903
50948
  const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical7(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical7(configPath), source)) : sources;
50904
50949
  const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
50905
- if (agent !== "claude" || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename8(source.path) !== "plugin.json" || !source.path.endsWith(join26(sep6, ".claude-plugin", "plugin.json")))
50950
+ if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename8(source.path) !== "plugin.json" || !source.path.endsWith(join26(sep6, ".claude-plugin", "plugin.json")))
50906
50951
  return source;
50907
50952
  const pluginRoot = dirname15(dirname15(source.path)), hooksPath = join26(pluginRoot, "hooks/hooks.json");
50908
50953
  const hookStat = lstatSync18(hooksPath, { throwIfNoEntry: false });
@@ -63996,6 +64041,24 @@ var init_http = __esm(() => {
63996
64041
  init_server3();
63997
64042
  });
63998
64043
 
64044
+ // src/lib/launch-cwd.ts
64045
+ var LAUNCH_CWD_VARIABLE = "HASNA_SKILLS_LAUNCH_CWD";
64046
+ function restoreLaunchCwd(env = process.env) {
64047
+ const requested = env[LAUNCH_CWD_VARIABLE];
64048
+ delete env[LAUNCH_CWD_VARIABLE];
64049
+ if (!requested || !requested.startsWith("/"))
64050
+ return { restored: false, cwd: process.cwd() };
64051
+ try {
64052
+ process.chdir(requested);
64053
+ return { restored: true, cwd: process.cwd() };
64054
+ } catch {
64055
+ return { restored: false, cwd: process.cwd() };
64056
+ }
64057
+ }
64058
+
64059
+ // src/lib/launch-cwd-apply.ts
64060
+ restoreLaunchCwd();
64061
+
63999
64062
  // src/mcp/index.ts
64000
64063
  init_stdio2();
64001
64064
  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.47",
28
+ version: "0.10.49",
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.47",
24143
+ version: "0.10.49",
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.47",
24146
+ version: "0.10.49",
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;
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env bun
2
- export {};
2
+ import "../lib/launch-cwd-apply.js";