@rynx-ai/skills 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/artifact.js CHANGED
@@ -121,14 +121,12 @@ export function parseSkillRefValue(value) {
121
121
  ...(typeof install.skill === "string" && install.skill ? { skill: install.skill } : {}),
122
122
  };
123
123
  }
124
- else if (install.tool === "npx") {
125
- if (typeof install.package !== "string" || !install.package.trim())
126
- return null;
127
- if (typeof install.version !== "string" || !install.version.trim())
124
+ else if (install.tool === "command") {
125
+ if (typeof install.command !== "string" || !install.command.trim())
128
126
  return null;
129
127
  if (!Array.isArray(install.args) || install.args.some((a) => typeof a !== "string"))
130
128
  return null;
131
- recipe = { tool: "npx", package: install.package, version: install.version, args: install.args };
129
+ recipe = { tool: "command", command: install.command, args: install.args };
132
130
  }
133
131
  else {
134
132
  return null;
package/dist/install.d.ts CHANGED
@@ -7,14 +7,16 @@ export interface InstalledSkill {
7
7
  dir: string;
8
8
  contentHash?: string;
9
9
  }
10
- /** Runs `npx <args>` with cwd = the temp install dir. Injectable (tests). */
11
- export type NpxRunner = (args: string[], opts: {
10
+ /** Runs `command args…` with cwd = the temp install dir. Injectable (tests). */
11
+ export type CommandRunner = (command: string, args: string[], opts: {
12
12
  cwd: string;
13
13
  }) => Promise<void>;
14
- /** Turn install params into the command line that performs them. Both tools
15
- * produce an `npx` invocation, run with cwd = the temp install dir. */
14
+ /** Turn install params into the `{ command, args }` that performs them, run
15
+ * with cwd = the temp install dir. skills-cli shells out through npx; the
16
+ * command recipe runs its executable directly. */
16
17
  export declare function buildInstallCommand(recipe: SkillInstallRecipe): {
17
- npxArgs: string[];
18
+ command: string;
19
+ args: string[];
18
20
  };
19
21
  /**
20
22
  * INSTALL ONLY: run `recipe`'s install command in a throwaway temp dir and
@@ -22,7 +24,7 @@ export declare function buildInstallCommand(recipe: SkillInstallRecipe): {
22
24
  * observations come back as the return value. Throws on bad input / failure.
23
25
  */
24
26
  export declare function installFromRecipe(recipe: SkillInstallRecipe, targetDir: string, opts?: {
25
- runNpx?: NpxRunner;
27
+ runCommand?: CommandRunner;
26
28
  }): Promise<InstalledSkill[]>;
27
29
  /** Write one skill dir's `.rynx-skill.json` v3 install-info file (catalog
28
30
  * artifact: the payload IS the SkillRef — declaration ≡ record, literally). */
@@ -33,5 +35,5 @@ export declare function writeSkillInstallInfo(skillDir: string, ref: SkillRef):
33
35
  * content hash. Returns the installed skills' catalog metadata.
34
36
  */
35
37
  export declare function installIntoCatalog(recipe: SkillInstallRecipe, catalogRoot: string, opts?: {
36
- runNpx?: NpxRunner;
38
+ runCommand?: CommandRunner;
37
39
  }): Promise<SkillMeta[]>;
package/dist/install.js CHANGED
@@ -17,9 +17,11 @@
17
17
  * write each produced skill an info file recording these exact params +
18
18
  * the observed hash.
19
19
  *
20
- * Every install bottoms out at `npx skills add` (the npx recipe variant is a
21
- * self-installing proxy that runs it in its cwd), so both tools share one
22
- * pickup path and one hash algorithm; they differ only in the command line.
20
+ * Every install runs a command in a throwaway temp dir that bottoms out at
21
+ * `skills add` (skills-cli shells out through `npx -y skills add …`; the command
22
+ * recipe runs a globally-installed self-installing proxy directly), so both
23
+ * share one pickup path (`.agents/skills/`) and one hash algorithm; they differ
24
+ * only in the command line.
23
25
  */
24
26
  import { execFile } from "node:child_process";
25
27
  import { cp, mkdir, mkdtemp, readdir, readFile, rm, writeFile } from "node:fs/promises";
@@ -27,8 +29,11 @@ import { tmpdir } from "node:os";
27
29
  import path from "node:path";
28
30
  import { promisify } from "node:util";
29
31
  import { readSkillMeta, SKILL_RECEIPT_FILE } from "./artifact.js";
30
- const runNpxDefault = async (args, opts) => {
31
- await promisify(execFile)("npx", args, { cwd: opts.cwd, timeout: 180_000 }).catch((err) => {
32
+ const runCommandDefault = async (command, args, opts) => {
33
+ await promisify(execFile)(command, args, { cwd: opts.cwd, timeout: 180_000 }).catch((err) => {
34
+ if (err.code === "ENOENT") {
35
+ throw new Error(`command not found: ${command} — install it (e.g. \`npm i -g @rynx-ai/emulator\` for rynx-emulator)`);
36
+ }
32
37
  throw new Error(`skills install failed: ${cliErrorDetail(err)}`);
33
38
  });
34
39
  };
@@ -40,8 +45,9 @@ function assertSafeArg(label, value) {
40
45
  if (/[;&|`$()<>\x00-\x1f]/.test(value))
41
46
  throw new Error(`invalid ${label}: ${value}`);
42
47
  }
43
- /** Turn install params into the command line that performs them. Both tools
44
- * produce an `npx` invocation, run with cwd = the temp install dir. */
48
+ /** Turn install params into the `{ command, args }` that performs them, run
49
+ * with cwd = the temp install dir. skills-cli shells out through npx; the
50
+ * command recipe runs its executable directly. */
45
51
  export function buildInstallCommand(recipe) {
46
52
  if (recipe.tool === "skills-cli") {
47
53
  const src = recipe.source.trim();
@@ -63,15 +69,13 @@ export function buildInstallCommand(recipe) {
63
69
  // predictable pickup location inside the throwaway temp dir. Which agent
64
70
  // actually sees a skill is decided downstream, at materialize time.
65
71
  args.push("--full-depth", "--agent", "universal", "--copy", "--yes");
66
- return { npxArgs: args };
72
+ return { command: "npx", args };
67
73
  }
68
- const pkg = recipe.package.trim();
69
- const version = recipe.version.trim();
70
- if (!pkg || !version)
71
- throw new Error("missing npx package/version");
72
- assertSafeArg("package", pkg);
73
- assertSafeArg("version", version);
74
- return { npxArgs: ["-y", `${pkg}@${version}`, ...recipe.args] };
74
+ const command = recipe.command.trim();
75
+ if (!command)
76
+ throw new Error("missing install command");
77
+ assertSafeArg("command", command);
78
+ return { command, args: recipe.args };
75
79
  }
76
80
  /**
77
81
  * INSTALL ONLY: run `recipe`'s install command in a throwaway temp dir and
@@ -79,7 +83,8 @@ export function buildInstallCommand(recipe) {
79
83
  * observations come back as the return value. Throws on bad input / failure.
80
84
  */
81
85
  export async function installFromRecipe(recipe, targetDir, opts = {}) {
82
- const staged = await execStagedInstall(buildInstallCommand(recipe).npxArgs, opts.runNpx);
86
+ const { command, args } = buildInstallCommand(recipe);
87
+ const staged = await execStagedInstall(command, args, opts.runCommand);
83
88
  try {
84
89
  if (staged.names.length === 0)
85
90
  throw new Error("no skill was installed — check the source identifier");
@@ -128,15 +133,15 @@ export async function installIntoCatalog(recipe, catalogRoot, opts = {}) {
128
133
  return metas;
129
134
  }
130
135
  /**
131
- * Run one `npx` command in a throwaway temp dir, list the skill folders it
136
+ * Run one install command in a throwaway temp dir, list the skill folders it
132
137
  * produced under `.agents/skills/`, and pick up the `skills` CLI's per-skill
133
138
  * content hashes from its `skills-lock.json`. The caller moves the folders
134
139
  * and owns the temp dir's cleanup.
135
140
  */
136
- async function execStagedInstall(npxArgs, runNpx = runNpxDefault) {
141
+ async function execStagedInstall(command, args, runCommand = runCommandDefault) {
137
142
  const staging = await mkdtemp(path.join(tmpdir(), "rynx-skill-"));
138
143
  try {
139
- await runNpx(npxArgs, { cwd: staging });
144
+ await runCommand(command, args, { cwd: staging });
140
145
  }
141
146
  catch (err) {
142
147
  await rm(staging, { recursive: true, force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rynx-ai/skills",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "The rynx skill artifact domain: discover/parse on-disk skills (SKILL.md), install them from replayable recipes (everything bottoms out at `npx skills add`), and read/write the catalog's `.rynx-skill.json` install-info files. Node built-ins + @rynx-ai/protocol only.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -21,7 +21,7 @@
21
21
  }
22
22
  },
23
23
  "dependencies": {
24
- "@rynx-ai/protocol": "0.1.0"
24
+ "@rynx-ai/protocol": "0.1.1"
25
25
  },
26
26
  "scripts": {
27
27
  "build": "rm -rf dist && tsc -p tsconfig.json"