rulesync 16.15.0 → 16.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_import = require("./import-nfDFI5X1.cjs");
2
+ const require_import = require("./import-DDPTPxOX.cjs");
3
3
  //#region src/index.ts
4
4
  async function generate(options = {}) {
5
5
  const { silent = true, verbose = false, ...rest } = options;
@@ -12,8 +12,9 @@ async function generate(options = {}) {
12
12
  verbose,
13
13
  silent
14
14
  });
15
- const inputRoot = config.getInputRoot();
16
- if (!await require_import.checkRulesyncDirExists({ inputRoot })) throw new Error(`.rulesync directory not found in '${inputRoot}'. Run 'rulesync init' first.`);
15
+ const inputRoots = config.getInputRoots();
16
+ const inputRootInspection = await require_import.inspectInputRoots(inputRoots);
17
+ if (inputRootInspection.message !== void 0) throw new Error(inputRootInspection.message);
17
18
  return require_import.generate({
18
19
  config,
19
20
  logger
package/dist/index.d.cts CHANGED
@@ -158,10 +158,87 @@ declare abstract class AiDir {
158
158
  getRelativePathFromCwd(): string;
159
159
  getGlobal(): boolean;
160
160
  setMainFile(name: string, body: string, frontmatter?: Record<string, unknown>): void;
161
+ /**
162
+ * A nested repository inside a carried directory is the one exclusion worth
163
+ * reporting: unlike `.DS_Store`, it is there on purpose, and the tree it
164
+ * points at is simply not reproduced on generate. Only the top level is
165
+ * checked, which is where a submodule or a stray `git init` puts it, so the
166
+ * check costs one stat per directory rather than a second walk. `fileExists`
167
+ * is a bare `stat`, so it answers for a submodule pointer file and for a real
168
+ * `.git` directory alike.
169
+ */
170
+ private static warnOnNestedGitDirectory;
171
+ /** Whether any segment of a relative path is dot-prefixed. */
172
+ private static hasHiddenSegment;
173
+ /**
174
+ * Whether the entry a path ends at is itself hidden, its ancestors aside.
175
+ * A shared skill tree usually lives under a dot-directory, so an ancestor
176
+ * says nothing about the file; its own name is what was chosen for it.
177
+ */
178
+ private static hasHiddenName;
179
+ /**
180
+ * Drop the entries a skill directory must not carry.
181
+ *
182
+ * Three rules. `classifyNeverCarried` comes first, evaluated against the
183
+ * resolved real path as well as the literal one: names that are never skill
184
+ * content stay out however they are reached, so renaming a symbolic link
185
+ * does not turn `~/.aws` into content a skill carries. Next, a real path
186
+ * inside a kernel pseudo-filesystem is refused outright — that is process
187
+ * state, not a file.
188
+ *
189
+ * The third concerns hidden entries a symbolic link reaches outside the
190
+ * directory. Following symlinks out of a source tree is deliberate and
191
+ * documented — it is how a shared skill is referenced from several projects
192
+ * without being duplicated (issue #1707), and the trust boundary is the tree
193
+ * you point Rulesync at. Carrying hidden entries changes what that costs,
194
+ * though: one ordinary-looking link to a home directory would pull in every
195
+ * dotfile under it, and those are the entries with credential value. What
196
+ * decides is the name in the skill directory, not what the link resolves
197
+ * through: a named file keeps its documented behavior even when the target
198
+ * sits under a dot-directory such as `~/.dotfiles`, because somebody chose
199
+ * that name. What the link resolves *to* still counts at the end of the path,
200
+ * though — `notes.md` pointing at `~/.claude/.credentials.json` reaches a
201
+ * file nobody named for a skill — so a hidden final segment is refused on
202
+ * either side. Reaching outside is reported either way, since content from
203
+ * outside the tree is about to be copied into every enabled tool root.
204
+ *
205
+ * A path that cannot be resolved is kept: `realpath` fails on a broken link
206
+ * or a race, and neither is a reason to silently drop a file.
207
+ */
208
+ /** Report what a carried directory left out, once both walks have had their say. */
209
+ private static warnOnRefusedCarriedFiles;
210
+ private static filterCarriedFiles;
211
+ /**
212
+ * Report what the walk had to leave behind, so a skill that silently lost
213
+ * files says so rather than generating a directory that is quietly short.
214
+ */
215
+ private static warnOnCarriedWalkLimits;
216
+ /**
217
+ * Walk the directory once more with the hidden routes pruned, and take the
218
+ * files the first walk had to leave behind because the route that reached
219
+ * them ran through a hidden directory. This can only add files, and only ones
220
+ * a fully named route reaches.
221
+ */
222
+ private static recoverCarriedFilesFromNamedRoutes;
161
223
  /**
162
224
  * Recursively collects all files from a directory, excluding the specified main file.
163
225
  * This is a common utility for loading additional files alongside the main file.
164
226
  *
227
+ * Hidden entries are included. The directories this walks are skill trees,
228
+ * whose specification says a skill directory "may contain any files and
229
+ * directories beyond the required `SKILL.md`" — a `.env.example` beside the
230
+ * scripts that read it is content, not noise, and dropping it silently on
231
+ * both import and generate loses part of the skill. What is left out is the
232
+ * set of entries that are never skill content — a nested repository's `.git`,
233
+ * the macOS Finder's `.DS_Store`, credential stores, build and cache trees —
234
+ * as decided by `classifyNeverCarried`. Whole directories from that set are
235
+ * pruned during the walk too, so it never descends into them at all.
236
+ *
237
+ * The walk is bounded and cycle-aware — see `walkCarriedFiles` — because the
238
+ * tree may contain symbolic links that somebody else chose.
239
+ *
240
+ * @see https://agentskills.io/specification
241
+ *
165
242
  * @param outputRoot - The base directory path
166
243
  * @param relativeDirPath - The relative path to the directory containing the skill
167
244
  * @param dirName - The name of the directory
@@ -364,6 +441,10 @@ declare const RulesyncSkillFrontmatterSchemaInternal: z.ZodMiniObject<{
364
441
  "user-invocable": z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
365
442
  enabled: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
366
443
  "allowed-tools": z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
444
+ license: z.ZodMiniOptional<z.ZodMiniUnknown>;
445
+ compatibility: z.ZodMiniOptional<z.ZodMiniUnknown>;
446
+ metadata: z.ZodMiniOptional<z.ZodMiniUnknown>;
447
+ version: z.ZodMiniOptional<z.ZodMiniUnknown>;
367
448
  }, z.core.$loose>>;
368
449
  grokcli: z.ZodMiniOptional<z.ZodMiniObject<{
369
450
  "disable-model-invocation": z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
@@ -543,6 +624,10 @@ type RulesyncSkillFrontmatterInput = {
543
624
  "user-invocable"?: boolean;
544
625
  enabled?: boolean;
545
626
  "allowed-tools"?: string | string[];
627
+ license?: unknown;
628
+ compatibility?: unknown;
629
+ metadata?: unknown;
630
+ version?: unknown;
546
631
  };
547
632
  "kimi-code"?: {
548
633
  type?: "prompt" | "inline" | "flow";
@@ -653,10 +738,24 @@ type GenerateOptions = BaseOptions & {
653
738
  features?: Feature[];
654
739
  outputRoots?: string[];
655
740
  /**
656
- * Directory containing the `.rulesync/` source files. Defaults to the
657
- * current working directory at config-construction time. When set, output
658
- * is still written to each `outputRoots` entry; only the input source root
659
- * is redirected. Mirrors the CLI's `--input-root` option.
741
+ * Ordered list of rulesync source-tree directories (e.g. `.rulesync`,
742
+ * `.rulesync.local`). Each entry is a source tree itself — the directory
743
+ * that directly contains `rules/`, `skills/`, `mcp.jsonc`, etc. No
744
+ * implicit `.rulesync/` join is applied. Defaults to
745
+ * `[join(process.cwd(), ".rulesync")]`. The first root is required; later
746
+ * roots are optional overlays and may be absent. Later entries override
747
+ * earlier ones when the same relative source path appears in more than one
748
+ * root. Mirrors the CLI's `--input-roots` option.
749
+ *
750
+ * Cannot be combined with `inputRoot`; use one or the other.
751
+ */
752
+ inputRoots?: string[];
753
+ /**
754
+ * @deprecated Use `inputRoots` instead. Kept as a backward-compatibility
755
+ * alias: the value is the PARENT directory of the default `.rulesync/`
756
+ * source tree, and internally expands to
757
+ * `inputRoots: [join(inputRoot, ".rulesync")]`. Mirrors the CLI's
758
+ * `--input-root` option. Cannot be combined with `inputRoots`.
660
759
  */
661
760
  inputRoot?: string;
662
761
  delete?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/features.ts","../src/types/tool-target-tuples.ts","../src/types/tool-targets.ts","../src/lib/convert.ts","../src/types/ai-dir.ts","../src/features/skills/rulesync-skill.ts","../src/lib/generate.ts","../src/lib/import.ts","../src/index.ts"],"mappings":";;cAaa;cA+BP,eAAa,EAAA,uBAAA,EAAA;;;;;;;;;IAAoE,EAAA;KAE3E,UAAU,EAAE,aAAa;;;cCiQxB;;;KCrSR,wBAAwB;cAEhB,4BAA4B,kBAAkB;cAM9C,kBAAgB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAEjB,aAAa,EAAE,aAAa;;;KCJ5B;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;KCrBU;EAEN;EACA;;EAGA;EACA,OAAO;;KAGD;EACV;EACA,YAAY;;;;;;;;EAQZ;;KAGU;EACV;EACA;EACA;EACA;IACE;IACA;IACA,cAAc;;EAEhB,aAAa;EACb;;KAGU,qBAAqB,KAC/B;uBAIoB;;;;qBAID;;;;qBAKA;;;;qBAKA;;;;YAKT;IACR;IACA;IACA,cAAc;;;;;YAMN,YAAY;;;;qBAKH;EAEnB,cACE,YACA,iBACA,SACA,UACA,YACA,UACC;SAcU,QAAQ,SAAS,qBAAqB,QAAQ;EAI3D;EAIA;EAIA;EAIA;EAqBA;IAEM;IACA;IACA,cAAc;;EAMpB,iBAAiB;;;;EAOjB;EAIA;EAIA,YAAY,cAAc,cAAc,cAAc;;;;;;;;;;;mBAc/B,kBACrB,oBACA,yBACA,iBACA,0BACC,QAAQ;WAmBF,YAAY;;;;cC7LjB,wCAAsC,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsR1C,EAAA,KAAA;KAMU;EACV;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,QAAQ;IACR;IACA;IACA;IACA;IACA;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;;EAEF;IACE;IACA;MACE;MACA;MACA;MACA;MACA;MACA;;IAEF;MACE;;IAEF;MACE,QAAQ;QACN;QACA;QACA;QACA;QACA;;;;EAIN;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;;EAEF;IACE;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;;EAEF;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb,MAAM;EACN,QAAQ;EACR,MAAM;EACN;IACE;IACA;IACA;IACA;IACA;IACA,cAAc;IACd;;EAEF;IACE;IACA;IACA;IACA;IACA;IACA;IACA,QAAQ;IACR;IACA;;EAEF;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA;IACA,WAAW;;EAEb;IACE;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA;;EAEF;IACE;IACA,yBAAyB;IACzB,WAAW;IACX;;EAEF,cAAc;EACd;IACE;IACA,yBAAyB;IACzB,WAAW;IACX;IACA;;EAEF;IACE;IACA;;;KAKQ,2BAA2B,EAAE,aAAa;KAO1C;EACV;EACA;EACA;EACA,aAAa;EACb;EACA,aAAa;EACb;EACA;;KAGU;EACV;;KAGU;EACV;EACA;EACA;EACA;;;;;;cAOW,sBAAsB;EACjC,cACE,YACA,iBACA,SACA,aACA,MACA,YACA,UACA,UACC;SAsBI,oBAAoB;EAU3B,kBAAkB;EAQlB;EAIA,YAAY;SAcC,UACX,YACA,iBACA,SACA,UACC,6BAA6B,QAAQ;;;;KCphB9B;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;;;;KCRU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;KC9CG;EACH;EACA;EACA;EACA;;KAGU,kBAAkB;EAC5B,UAAU;EACV,WAAW;EACX;;;;;;;EAOA;EACA;EACA;EACA;EACA;EACA;EACA;;KAGU,gBAAgB;EAC1B,QAAQ;EACR,WAAW;;KAGD,iBAAiB;EAC3B,MAAM;EACN,IAAI;EACJ,WAAW;EACX;;iBAGoB,SAAS,UAAS,kBAAuB,QAAQ;iBAqBjD,eAAe,SAAS,gBAAgB,QAAQ;iBAehD,gBAAgB,SAAS,iBAAiB,QAAQ"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/features.ts","../src/types/tool-target-tuples.ts","../src/types/tool-targets.ts","../src/lib/convert.ts","../src/types/ai-dir.ts","../src/features/skills/rulesync-skill.ts","../src/lib/generate.ts","../src/lib/import.ts","../src/index.ts"],"mappings":";;cAaa;cA+BP,eAAa,EAAA,uBAAA,EAAA;;;;;;;;;IAAoE,EAAA;KAE3E,UAAU,EAAE,aAAa;;;cCiQxB;;;KCrSR,wBAAwB;cAEhB,4BAA4B,kBAAkB;cAM9C,kBAAgB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAEjB,aAAa,EAAE,aAAa;;;KCH5B;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;KCTU;EAEN;EACA;;EAGA;EACA,OAAO;;KAGD;EACV;EACA,YAAY;;;;;;;;EAQZ;;KAmnBU;EACV;EACA;EACA;EACA;IACE;IACA;IACA,cAAc;;EAEhB,aAAa;EACb;;KAGU,qBAAqB,KAC/B;uBAIoB;;;;qBAID;;;;qBAKA;;;;qBAKA;;;;YAKT;IACR;IACA;IACA,cAAc;;;;;YAMN,YAAY;;;;qBAKH;EAEnB,cACE,YACA,iBACA,SACA,UACA,YACA,UACC;SAcU,QAAQ,SAAS,qBAAqB,QAAQ;EAI3D;EAIA;EAIA;EAIA;EAqBA;IAEM;IACA;IACA,cAAc;;EAMpB,iBAAiB;;;;EAOjB;EAIA;EAIA,YAAY,cAAc,cAAc,cAAc;;;;;;;;;;iBAajC;;iBAWN;;;;;;iBASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkCA;iBA8CM;;;;;iBA6GN;;;;;;;iBAgDM;;;;;;;;;;;;;;;;;;;;;;;;;;mBA+FE,kBACrB,oBACA,yBACA,iBACA,0BACC,QAAQ;WAmGF,YAAY;;;;cCzuCjB,wCAAsC,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8R1C,EAAA,KAAA;KAMU;EACV;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,QAAQ;IACR;IACA;IACA;IACA;IACA;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;;EAEF;IACE;IACA;MACE;MACA;MACA;MACA;MACA;MACA;;IAEF;MACE;;IAEF;MACE,QAAQ;QACN;QACA;QACA;QACA;QACA;;;;EAIN;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;;EAEF;IACE;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;;EAEF;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb,MAAM;EACN,QAAQ;EACR,MAAM;EACN;IACE;IACA;IACA;IACA;IACA;IACA,cAAc;IACd;;EAEF;IACE;IACA;IACA;IACA;IACA;IACA;IACA,QAAQ;IACR;IACA;;EAEF;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA;IACA,WAAW;;EAEb;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA;;EAEF;IACE;IACA,yBAAyB;IACzB,WAAW;IACX;;EAEF,cAAc;EACd;IACE;IACA,yBAAyB;IACzB,WAAW;IACX;IACA;;EAEF;IACE;IACA;;;KAKQ,2BAA2B,EAAE,aAAa;KAO1C;EACV;EACA;EACA;EACA,aAAa;EACb;EACA,aAAa;EACb;EACA;;KAGU;EACV;;KAGU;EACV;EACA;EACA;EACA;;;;;;cAOW,sBAAsB;EACjC,cACE,YACA,iBACA,SACA,aACA,MACA,YACA,UACA,UACC;SAsBI,oBAAoB;EAU3B,kBAAkB;EAQlB;EAIA,YAAY;SAcC,UACX,YACA,iBACA,SACA,UACC,6BAA6B,QAAQ;;;;KC9hB9B;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;;;;KCTU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;KC/CG;EACH;EACA;EACA;EACA;;KAGU,kBAAkB;EAC5B,UAAU;EACV,WAAW;EACX;;;;;;;;;;;;;EAaA;;;;;;;;EAQA;EACA;EACA;EACA;EACA;EACA;EACA;;KAGU,gBAAgB;EAC1B,QAAQ;EACR,WAAW;;KAGD,iBAAiB;EAC3B,MAAM;EACN,IAAI;EACJ,WAAW;EACX;;iBAGoB,SAAS,UAAS,kBAAuB,QAAQ;iBAyBjD,eAAe,SAAS,gBAAgB,QAAQ;iBAehD,gBAAgB,SAAS,iBAAiB,QAAQ"}
package/dist/index.d.ts CHANGED
@@ -158,10 +158,87 @@ declare abstract class AiDir {
158
158
  getRelativePathFromCwd(): string;
159
159
  getGlobal(): boolean;
160
160
  setMainFile(name: string, body: string, frontmatter?: Record<string, unknown>): void;
161
+ /**
162
+ * A nested repository inside a carried directory is the one exclusion worth
163
+ * reporting: unlike `.DS_Store`, it is there on purpose, and the tree it
164
+ * points at is simply not reproduced on generate. Only the top level is
165
+ * checked, which is where a submodule or a stray `git init` puts it, so the
166
+ * check costs one stat per directory rather than a second walk. `fileExists`
167
+ * is a bare `stat`, so it answers for a submodule pointer file and for a real
168
+ * `.git` directory alike.
169
+ */
170
+ private static warnOnNestedGitDirectory;
171
+ /** Whether any segment of a relative path is dot-prefixed. */
172
+ private static hasHiddenSegment;
173
+ /**
174
+ * Whether the entry a path ends at is itself hidden, its ancestors aside.
175
+ * A shared skill tree usually lives under a dot-directory, so an ancestor
176
+ * says nothing about the file; its own name is what was chosen for it.
177
+ */
178
+ private static hasHiddenName;
179
+ /**
180
+ * Drop the entries a skill directory must not carry.
181
+ *
182
+ * Three rules. `classifyNeverCarried` comes first, evaluated against the
183
+ * resolved real path as well as the literal one: names that are never skill
184
+ * content stay out however they are reached, so renaming a symbolic link
185
+ * does not turn `~/.aws` into content a skill carries. Next, a real path
186
+ * inside a kernel pseudo-filesystem is refused outright — that is process
187
+ * state, not a file.
188
+ *
189
+ * The third concerns hidden entries a symbolic link reaches outside the
190
+ * directory. Following symlinks out of a source tree is deliberate and
191
+ * documented — it is how a shared skill is referenced from several projects
192
+ * without being duplicated (issue #1707), and the trust boundary is the tree
193
+ * you point Rulesync at. Carrying hidden entries changes what that costs,
194
+ * though: one ordinary-looking link to a home directory would pull in every
195
+ * dotfile under it, and those are the entries with credential value. What
196
+ * decides is the name in the skill directory, not what the link resolves
197
+ * through: a named file keeps its documented behavior even when the target
198
+ * sits under a dot-directory such as `~/.dotfiles`, because somebody chose
199
+ * that name. What the link resolves *to* still counts at the end of the path,
200
+ * though — `notes.md` pointing at `~/.claude/.credentials.json` reaches a
201
+ * file nobody named for a skill — so a hidden final segment is refused on
202
+ * either side. Reaching outside is reported either way, since content from
203
+ * outside the tree is about to be copied into every enabled tool root.
204
+ *
205
+ * A path that cannot be resolved is kept: `realpath` fails on a broken link
206
+ * or a race, and neither is a reason to silently drop a file.
207
+ */
208
+ /** Report what a carried directory left out, once both walks have had their say. */
209
+ private static warnOnRefusedCarriedFiles;
210
+ private static filterCarriedFiles;
211
+ /**
212
+ * Report what the walk had to leave behind, so a skill that silently lost
213
+ * files says so rather than generating a directory that is quietly short.
214
+ */
215
+ private static warnOnCarriedWalkLimits;
216
+ /**
217
+ * Walk the directory once more with the hidden routes pruned, and take the
218
+ * files the first walk had to leave behind because the route that reached
219
+ * them ran through a hidden directory. This can only add files, and only ones
220
+ * a fully named route reaches.
221
+ */
222
+ private static recoverCarriedFilesFromNamedRoutes;
161
223
  /**
162
224
  * Recursively collects all files from a directory, excluding the specified main file.
163
225
  * This is a common utility for loading additional files alongside the main file.
164
226
  *
227
+ * Hidden entries are included. The directories this walks are skill trees,
228
+ * whose specification says a skill directory "may contain any files and
229
+ * directories beyond the required `SKILL.md`" — a `.env.example` beside the
230
+ * scripts that read it is content, not noise, and dropping it silently on
231
+ * both import and generate loses part of the skill. What is left out is the
232
+ * set of entries that are never skill content — a nested repository's `.git`,
233
+ * the macOS Finder's `.DS_Store`, credential stores, build and cache trees —
234
+ * as decided by `classifyNeverCarried`. Whole directories from that set are
235
+ * pruned during the walk too, so it never descends into them at all.
236
+ *
237
+ * The walk is bounded and cycle-aware — see `walkCarriedFiles` — because the
238
+ * tree may contain symbolic links that somebody else chose.
239
+ *
240
+ * @see https://agentskills.io/specification
241
+ *
165
242
  * @param outputRoot - The base directory path
166
243
  * @param relativeDirPath - The relative path to the directory containing the skill
167
244
  * @param dirName - The name of the directory
@@ -364,6 +441,10 @@ declare const RulesyncSkillFrontmatterSchemaInternal: z.ZodMiniObject<{
364
441
  "user-invocable": z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
365
442
  enabled: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
366
443
  "allowed-tools": z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
444
+ license: z.ZodMiniOptional<z.ZodMiniUnknown>;
445
+ compatibility: z.ZodMiniOptional<z.ZodMiniUnknown>;
446
+ metadata: z.ZodMiniOptional<z.ZodMiniUnknown>;
447
+ version: z.ZodMiniOptional<z.ZodMiniUnknown>;
367
448
  }, z.core.$loose>>;
368
449
  grokcli: z.ZodMiniOptional<z.ZodMiniObject<{
369
450
  "disable-model-invocation": z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
@@ -543,6 +624,10 @@ type RulesyncSkillFrontmatterInput = {
543
624
  "user-invocable"?: boolean;
544
625
  enabled?: boolean;
545
626
  "allowed-tools"?: string | string[];
627
+ license?: unknown;
628
+ compatibility?: unknown;
629
+ metadata?: unknown;
630
+ version?: unknown;
546
631
  };
547
632
  "kimi-code"?: {
548
633
  type?: "prompt" | "inline" | "flow";
@@ -653,10 +738,24 @@ type GenerateOptions = BaseOptions & {
653
738
  features?: Feature[];
654
739
  outputRoots?: string[];
655
740
  /**
656
- * Directory containing the `.rulesync/` source files. Defaults to the
657
- * current working directory at config-construction time. When set, output
658
- * is still written to each `outputRoots` entry; only the input source root
659
- * is redirected. Mirrors the CLI's `--input-root` option.
741
+ * Ordered list of rulesync source-tree directories (e.g. `.rulesync`,
742
+ * `.rulesync.local`). Each entry is a source tree itself — the directory
743
+ * that directly contains `rules/`, `skills/`, `mcp.jsonc`, etc. No
744
+ * implicit `.rulesync/` join is applied. Defaults to
745
+ * `[join(process.cwd(), ".rulesync")]`. The first root is required; later
746
+ * roots are optional overlays and may be absent. Later entries override
747
+ * earlier ones when the same relative source path appears in more than one
748
+ * root. Mirrors the CLI's `--input-roots` option.
749
+ *
750
+ * Cannot be combined with `inputRoot`; use one or the other.
751
+ */
752
+ inputRoots?: string[];
753
+ /**
754
+ * @deprecated Use `inputRoots` instead. Kept as a backward-compatibility
755
+ * alias: the value is the PARENT directory of the default `.rulesync/`
756
+ * source tree, and internally expands to
757
+ * `inputRoots: [join(inputRoot, ".rulesync")]`. Mirrors the CLI's
758
+ * `--input-root` option. Cannot be combined with `inputRoots`.
660
759
  */
661
760
  inputRoot?: string;
662
761
  delete?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/features.ts","../src/types/tool-target-tuples.ts","../src/types/tool-targets.ts","../src/lib/convert.ts","../src/types/ai-dir.ts","../src/features/skills/rulesync-skill.ts","../src/lib/generate.ts","../src/lib/import.ts","../src/index.ts"],"mappings":";;cAaa;cA+BP,eAAa,EAAA,uBAAA,EAAA;;;;;;;;;IAAoE,EAAA;KAE3E,UAAU,EAAE,aAAa;;;cCiQxB;;;KCrSR,wBAAwB;cAEhB,4BAA4B,kBAAkB;cAM9C,kBAAgB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAEjB,aAAa,EAAE,aAAa;;;KCJ5B;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;KCrBU;EAEN;EACA;;EAGA;EACA,OAAO;;KAGD;EACV;EACA,YAAY;;;;;;;;EAQZ;;KAGU;EACV;EACA;EACA;EACA;IACE;IACA;IACA,cAAc;;EAEhB,aAAa;EACb;;KAGU,qBAAqB,KAC/B;uBAIoB;;;;qBAID;;;;qBAKA;;;;qBAKA;;;;YAKT;IACR;IACA;IACA,cAAc;;;;;YAMN,YAAY;;;;qBAKH;EAEnB,cACE,YACA,iBACA,SACA,UACA,YACA,UACC;SAcU,QAAQ,SAAS,qBAAqB,QAAQ;EAI3D;EAIA;EAIA;EAIA;EAqBA;IAEM;IACA;IACA,cAAc;;EAMpB,iBAAiB;;;;EAOjB;EAIA;EAIA,YAAY,cAAc,cAAc,cAAc;;;;;;;;;;;mBAc/B,kBACrB,oBACA,yBACA,iBACA,0BACC,QAAQ;WAmBF,YAAY;;;;cC7LjB,wCAAsC,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsR1C,EAAA,KAAA;KAMU;EACV;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,QAAQ;IACR;IACA;IACA;IACA;IACA;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;;EAEF;IACE;IACA;MACE;MACA;MACA;MACA;MACA;MACA;;IAEF;MACE;;IAEF;MACE,QAAQ;QACN;QACA;QACA;QACA;QACA;;;;EAIN;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;;EAEF;IACE;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;;EAEF;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb,MAAM;EACN,QAAQ;EACR,MAAM;EACN;IACE;IACA;IACA;IACA;IACA;IACA,cAAc;IACd;;EAEF;IACE;IACA;IACA;IACA;IACA;IACA;IACA,QAAQ;IACR;IACA;;EAEF;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA;IACA,WAAW;;EAEb;IACE;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA;;EAEF;IACE;IACA,yBAAyB;IACzB,WAAW;IACX;;EAEF,cAAc;EACd;IACE;IACA,yBAAyB;IACzB,WAAW;IACX;IACA;;EAEF;IACE;IACA;;;KAKQ,2BAA2B,EAAE,aAAa;KAO1C;EACV;EACA;EACA;EACA,aAAa;EACb;EACA,aAAa;EACb;EACA;;KAGU;EACV;;KAGU;EACV;EACA;EACA;EACA;;;;;;cAOW,sBAAsB;EACjC,cACE,YACA,iBACA,SACA,aACA,MACA,YACA,UACA,UACC;SAsBI,oBAAoB;EAU3B,kBAAkB;EAQlB;EAIA,YAAY;SAcC,UACX,YACA,iBACA,SACA,UACC,6BAA6B,QAAQ;;;;KCphB9B;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;;;;KCRU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;KC9CG;EACH;EACA;EACA;EACA;;KAGU,kBAAkB;EAC5B,UAAU;EACV,WAAW;EACX;;;;;;;EAOA;EACA;EACA;EACA;EACA;EACA;EACA;;KAGU,gBAAgB;EAC1B,QAAQ;EACR,WAAW;;KAGD,iBAAiB;EAC3B,MAAM;EACN,IAAI;EACJ,WAAW;EACX;;iBAGoB,SAAS,UAAS,kBAAuB,QAAQ;iBAqBjD,eAAe,SAAS,gBAAgB,QAAQ;iBAehD,gBAAgB,SAAS,iBAAiB,QAAQ"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/features.ts","../src/types/tool-target-tuples.ts","../src/types/tool-targets.ts","../src/lib/convert.ts","../src/types/ai-dir.ts","../src/features/skills/rulesync-skill.ts","../src/lib/generate.ts","../src/lib/import.ts","../src/index.ts"],"mappings":";;cAaa;cA+BP,eAAa,EAAA,uBAAA,EAAA;;;;;;;;;IAAoE,EAAA;KAE3E,UAAU,EAAE,aAAa;;;cCiQxB;;;KCrSR,wBAAwB;cAEhB,4BAA4B,kBAAkB;cAM9C,kBAAgB,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAEjB,aAAa,EAAE,aAAa;;;KCH5B;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;KCTU;EAEN;EACA;;EAGA;EACA,OAAO;;KAGD;EACV;EACA,YAAY;;;;;;;;EAQZ;;KAmnBU;EACV;EACA;EACA;EACA;IACE;IACA;IACA,cAAc;;EAEhB,aAAa;EACb;;KAGU,qBAAqB,KAC/B;uBAIoB;;;;qBAID;;;;qBAKA;;;;qBAKA;;;;YAKT;IACR;IACA;IACA,cAAc;;;;;YAMN,YAAY;;;;qBAKH;EAEnB,cACE,YACA,iBACA,SACA,UACA,YACA,UACC;SAcU,QAAQ,SAAS,qBAAqB,QAAQ;EAI3D;EAIA;EAIA;EAIA;EAqBA;IAEM;IACA;IACA,cAAc;;EAMpB,iBAAiB;;;;EAOjB;EAIA;EAIA,YAAY,cAAc,cAAc,cAAc;;;;;;;;;;iBAajC;;iBAWN;;;;;;iBASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkCA;iBA8CM;;;;;iBA6GN;;;;;;;iBAgDM;;;;;;;;;;;;;;;;;;;;;;;;;;mBA+FE,kBACrB,oBACA,yBACA,iBACA,0BACC,QAAQ;WAmGF,YAAY;;;;cCzuCjB,wCAAsC,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8R1C,EAAA,KAAA;KAMU;EACV;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,QAAQ;IACR;IACA;IACA;IACA;IACA;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;;EAEF;IACE;IACA;MACE;MACA;MACA;MACA;MACA;MACA;;IAEF;MACE;;IAEF;MACE,QAAQ;QACN;QACA;QACA;QACA;QACA;;;;EAIN;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;;EAEF;IACE;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;;EAEF;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb,MAAM;EACN,QAAQ;EACR,MAAM;EACN;IACE;IACA;IACA;IACA;IACA;IACA,cAAc;IACd;;EAEF;IACE;IACA;IACA;IACA;IACA;IACA;IACA,QAAQ;IACR;IACA;;EAEF;IACE;IACA;IACA,yBAAyB;IACzB,WAAW;;EAEb;IACE;IACA;IACA;IACA,WAAW;;EAEb;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEF;IACE;IACA;IACA;IACA;;EAEF;IACE;IACA,yBAAyB;IACzB,WAAW;IACX;;EAEF,cAAc;EACd;IACE;IACA,yBAAyB;IACzB,WAAW;IACX;IACA;;EAEF;IACE;IACA;;;KAKQ,2BAA2B,EAAE,aAAa;KAO1C;EACV;EACA;EACA;EACA,aAAa;EACb;EACA,aAAa;EACb;EACA;;KAGU;EACV;;KAGU;EACV;EACA;EACA;EACA;;;;;;cAOW,sBAAsB;EACjC,cACE,YACA,iBACA,SACA,aACA,MACA,YACA,UACA,UACC;SAsBI,oBAAoB;EAU3B,kBAAkB;EAQlB;EAIA,YAAY;SAcC,UACX,YACA,iBACA,SACA,UACC,6BAA6B,QAAQ;;;;KC9hB9B;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;;;;KCTU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;KC/CG;EACH;EACA;EACA;EACA;;KAGU,kBAAkB;EAC5B,UAAU;EACV,WAAW;EACX;;;;;;;;;;;;;EAaA;;;;;;;;EAQA;EACA;EACA;EACA;EACA;EACA;EACA;;KAGU,gBAAgB;EAC1B,QAAQ;EACR,WAAW;;KAGD,iBAAiB;EAC3B,MAAM;EACN,IAAI;EACJ,WAAW;EACX;;iBAGoB,SAAS,UAAS,kBAAuB,QAAQ;iBAyBjD,eAAe,SAAS,gBAAgB,QAAQ;iBAehD,gBAAgB,SAAS,iBAAiB,QAAQ"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as ConsoleLogger, At as ALL_TOOL_TARGETS, a as convertFromTool$1, cn as ALL_FEATURES, n as checkRulesyncDirExists, q as ConfigResolver, r as generate$1, t as importFromTool$1 } from "./import-BPTCMtUS.js";
1
+ import { Pt as ALL_TOOL_TARGETS, a as convertFromTool$1, fn as ALL_FEATURES, n as generate$1, q as ConfigResolver, r as inspectInputRoots, t as importFromTool$1, tt as ConsoleLogger } from "./import-u8yswsGB.js";
2
2
  //#region src/index.ts
3
3
  async function generate(options = {}) {
4
4
  const { silent = true, verbose = false, ...rest } = options;
@@ -11,8 +11,9 @@ async function generate(options = {}) {
11
11
  verbose,
12
12
  silent
13
13
  });
14
- const inputRoot = config.getInputRoot();
15
- if (!await checkRulesyncDirExists({ inputRoot })) throw new Error(`.rulesync directory not found in '${inputRoot}'. Run 'rulesync init' first.`);
14
+ const inputRoots = config.getInputRoots();
15
+ const inputRootInspection = await inspectInputRoots(inputRoots);
16
+ if (inputRootInspection.message !== void 0) throw new Error(inputRootInspection.message);
16
17
  return generate$1({
17
18
  config,
18
19
  logger
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["coreGenerate","coreImportFromTool","coreConvertFromTool"],"sources":["../src/index.ts"],"sourcesContent":["import { ConfigResolver } from \"./config/config-resolver.js\";\nimport { convertFromTool as coreConvertFromTool, type ConvertResult } from \"./lib/convert.js\";\nimport {\n checkRulesyncDirExists,\n generate as coreGenerate,\n type GenerateResult,\n} from \"./lib/generate.js\";\nimport { importFromTool as coreImportFromTool, type ImportResult } from \"./lib/import.js\";\nimport type { Feature } from \"./types/features.js\";\nimport type { ToolTarget } from \"./types/tool-targets.js\";\nimport { ConsoleLogger } from \"./utils/logger.js\";\n\nexport type { Feature } from \"./types/features.js\";\nexport type { ToolTarget } from \"./types/tool-targets.js\";\nexport { ALL_FEATURES } from \"./types/features.js\";\nexport { ALL_TOOL_TARGETS } from \"./types/tool-targets.js\";\nexport type { GenerateResult } from \"./lib/generate.js\";\nexport type { ImportResult } from \"./lib/import.js\";\nexport type { ConvertResult } from \"./lib/convert.js\";\n\ntype BaseOptions = {\n configPath?: string;\n verbose?: boolean;\n silent?: boolean;\n global?: boolean;\n};\n\nexport type GenerateOptions = BaseOptions & {\n targets?: ToolTarget[];\n features?: Feature[];\n outputRoots?: string[];\n /**\n * Directory containing the `.rulesync/` source files. Defaults to the\n * current working directory at config-construction time. When set, output\n * is still written to each `outputRoots` entry; only the input source root\n * is redirected. Mirrors the CLI's `--input-root` option.\n */\n inputRoot?: string;\n delete?: boolean;\n simulateCommands?: boolean;\n simulateSubagents?: boolean;\n simulateSkills?: boolean;\n dryRun?: boolean;\n check?: boolean;\n};\n\nexport type ImportOptions = BaseOptions & {\n target: ToolTarget;\n features?: Feature[];\n};\n\nexport type ConvertOptions = BaseOptions & {\n from: ToolTarget;\n to: ToolTarget[];\n features?: Feature[];\n dryRun?: boolean;\n};\n\nexport async function generate(options: GenerateOptions = {}): Promise<GenerateResult> {\n const { silent = true, verbose = false, ...rest } = options;\n const logger = new ConsoleLogger({ verbose, silent });\n\n const config = await ConfigResolver.resolve({\n ...rest,\n verbose,\n silent,\n });\n\n // The pre-flight check probes the input source root rather than each\n // output root. This matches the CLI's behavior and the way features\n // load `.rulesync/**` content (always relative to `config.getInputRoot()`).\n const inputRoot = config.getInputRoot();\n if (!(await checkRulesyncDirExists({ inputRoot }))) {\n throw new Error(`.rulesync directory not found in '${inputRoot}'. Run 'rulesync init' first.`);\n }\n\n return coreGenerate({ config, logger });\n}\n\nexport async function importFromTool(options: ImportOptions): Promise<ImportResult> {\n const { target, features, silent = true, verbose = false, ...rest } = options;\n const logger = new ConsoleLogger({ verbose, silent });\n\n const config = await ConfigResolver.resolve({\n ...rest,\n targets: [target],\n features,\n verbose,\n silent,\n });\n\n return coreImportFromTool({ config, tool: target, logger });\n}\n\nexport async function convertFromTool(options: ConvertOptions): Promise<ConvertResult> {\n const { from, to, features, silent = true, verbose = false, ...rest } = options;\n\n if (!from) {\n throw new Error(\"from is required. Please specify a source tool to convert from.\");\n }\n\n if (!to || to.length === 0) {\n throw new Error(\"to is required and must not be empty. Please specify destination tools.\");\n }\n\n const toTools = Array.from(new Set(to));\n\n if (toTools.includes(from)) {\n throw new Error(\n `Destination tools must not include the source tool '${from}'. ` +\n `Converting a tool onto itself is likely a mistake and may cause lossy round-trips.`,\n );\n }\n\n const logger = new ConsoleLogger({ verbose, silent });\n\n // NOTE: The CLI and MCP wrappers pass `[from, ...to]` as `targets` so that\n // per-target feature overrides in `rulesync.jsonc` apply to destinations too.\n // The JS API intentionally passes only `[from]` here because the public\n // contract for `convertFromTool` (issue #1557) prescribes this shape:\n // programmatic callers are expected to supply `features` explicitly when\n // they need fine-grained control, rather than relying on config-file\n // per-target maps. Defaulting `features` to `[\"*\"]` below matches the CLI's\n // \"attempt every feature both tools support\" behavior so callers who omit\n // `features` get the same effective coverage as the CLI.\n const config = await ConfigResolver.resolve({\n ...rest,\n targets: [from],\n features: features ?? [\"*\"],\n verbose,\n silent,\n });\n\n return coreConvertFromTool({ config, fromTool: from, toTools, logger });\n}\n"],"mappings":";;AA0DA,eAAsB,SAAS,UAA2B,CAAC,GAA4B;CACrF,MAAM,EAAE,SAAS,MAAM,UAAU,OAAO,GAAG,SAAS;CACpD,MAAM,SAAS,IAAI,cAAc;EAAE;EAAS;CAAO,CAAC;CAEpD,MAAM,SAAS,MAAM,eAAe,QAAQ;EAC1C,GAAG;EACH;EACA;CACF,CAAC;CAKD,MAAM,YAAY,OAAO,aAAa;CACtC,IAAI,CAAE,MAAM,uBAAuB,EAAE,UAAU,CAAC,GAC9C,MAAM,IAAI,MAAM,qCAAqC,UAAU,8BAA8B;CAG/F,OAAOA,WAAa;EAAE;EAAQ;CAAO,CAAC;AACxC;AAEA,eAAsB,eAAe,SAA+C;CAClF,MAAM,EAAE,QAAQ,UAAU,SAAS,MAAM,UAAU,OAAO,GAAG,SAAS;CACtE,MAAM,SAAS,IAAI,cAAc;EAAE;EAAS;CAAO,CAAC;CAEpD,MAAM,SAAS,MAAM,eAAe,QAAQ;EAC1C,GAAG;EACH,SAAS,CAAC,MAAM;EAChB;EACA;EACA;CACF,CAAC;CAED,OAAOC,iBAAmB;EAAE;EAAQ,MAAM;EAAQ;CAAO,CAAC;AAC5D;AAEA,eAAsB,gBAAgB,SAAiD;CACrF,MAAM,EAAE,MAAM,IAAI,UAAU,SAAS,MAAM,UAAU,OAAO,GAAG,SAAS;CAExE,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,iEAAiE;CAGnF,IAAI,CAAC,MAAM,GAAG,WAAW,GACvB,MAAM,IAAI,MAAM,yEAAyE;CAG3F,MAAM,UAAU,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;CAEtC,IAAI,QAAQ,SAAS,IAAI,GACvB,MAAM,IAAI,MACR,uDAAuD,KAAK,sFAE9D;CAGF,MAAM,SAAS,IAAI,cAAc;EAAE;EAAS;CAAO,CAAC;CAWpD,MAAM,SAAS,MAAM,eAAe,QAAQ;EAC1C,GAAG;EACH,SAAS,CAAC,IAAI;EACd,UAAU,YAAY,CAAC,GAAG;EAC1B;EACA;CACF,CAAC;CAED,OAAOC,kBAAoB;EAAE;EAAQ,UAAU;EAAM;EAAS;CAAO,CAAC;AACxE"}
1
+ {"version":3,"file":"index.js","names":["coreGenerate","coreImportFromTool","coreConvertFromTool"],"sources":["../src/index.ts"],"sourcesContent":["import { ConfigResolver } from \"./config/config-resolver.js\";\nimport { convertFromTool as coreConvertFromTool, type ConvertResult } from \"./lib/convert.js\";\nimport {\n generate as coreGenerate,\n inspectInputRoots,\n type GenerateResult,\n} from \"./lib/generate.js\";\nimport { importFromTool as coreImportFromTool, type ImportResult } from \"./lib/import.js\";\nimport type { Feature } from \"./types/features.js\";\nimport type { ToolTarget } from \"./types/tool-targets.js\";\nimport { ConsoleLogger } from \"./utils/logger.js\";\n\nexport type { Feature } from \"./types/features.js\";\nexport type { ToolTarget } from \"./types/tool-targets.js\";\nexport { ALL_FEATURES } from \"./types/features.js\";\nexport { ALL_TOOL_TARGETS } from \"./types/tool-targets.js\";\nexport type { GenerateResult } from \"./lib/generate.js\";\nexport type { ImportResult } from \"./lib/import.js\";\nexport type { ConvertResult } from \"./lib/convert.js\";\n\ntype BaseOptions = {\n configPath?: string;\n verbose?: boolean;\n silent?: boolean;\n global?: boolean;\n};\n\nexport type GenerateOptions = BaseOptions & {\n targets?: ToolTarget[];\n features?: Feature[];\n outputRoots?: string[];\n /**\n * Ordered list of rulesync source-tree directories (e.g. `.rulesync`,\n * `.rulesync.local`). Each entry is a source tree itself — the directory\n * that directly contains `rules/`, `skills/`, `mcp.jsonc`, etc. No\n * implicit `.rulesync/` join is applied. Defaults to\n * `[join(process.cwd(), \".rulesync\")]`. The first root is required; later\n * roots are optional overlays and may be absent. Later entries override\n * earlier ones when the same relative source path appears in more than one\n * root. Mirrors the CLI's `--input-roots` option.\n *\n * Cannot be combined with `inputRoot`; use one or the other.\n */\n inputRoots?: string[];\n /**\n * @deprecated Use `inputRoots` instead. Kept as a backward-compatibility\n * alias: the value is the PARENT directory of the default `.rulesync/`\n * source tree, and internally expands to\n * `inputRoots: [join(inputRoot, \".rulesync\")]`. Mirrors the CLI's\n * `--input-root` option. Cannot be combined with `inputRoots`.\n */\n inputRoot?: string;\n delete?: boolean;\n simulateCommands?: boolean;\n simulateSubagents?: boolean;\n simulateSkills?: boolean;\n dryRun?: boolean;\n check?: boolean;\n};\n\nexport type ImportOptions = BaseOptions & {\n target: ToolTarget;\n features?: Feature[];\n};\n\nexport type ConvertOptions = BaseOptions & {\n from: ToolTarget;\n to: ToolTarget[];\n features?: Feature[];\n dryRun?: boolean;\n};\n\nexport async function generate(options: GenerateOptions = {}): Promise<GenerateResult> {\n const { silent = true, verbose = false, ...rest } = options;\n const logger = new ConsoleLogger({ verbose, silent });\n\n const config = await ConfigResolver.resolve({\n ...rest,\n verbose,\n silent,\n });\n\n // The pre-flight check probes the input source roots rather than each output\n // root. This matches the CLI's behavior and the way features load content\n // relative to `config.getInputRoots()`. Empty source roots are allowed so\n // `generate --delete --check` can still detect orphaned outputs.\n const inputRoots = config.getInputRoots();\n\n const inputRootInspection = await inspectInputRoots(inputRoots);\n\n if (inputRootInspection.message !== undefined) {\n throw new Error(inputRootInspection.message);\n }\n\n return coreGenerate({ config, logger });\n}\n\nexport async function importFromTool(options: ImportOptions): Promise<ImportResult> {\n const { target, features, silent = true, verbose = false, ...rest } = options;\n const logger = new ConsoleLogger({ verbose, silent });\n\n const config = await ConfigResolver.resolve({\n ...rest,\n targets: [target],\n features,\n verbose,\n silent,\n });\n\n return coreImportFromTool({ config, tool: target, logger });\n}\n\nexport async function convertFromTool(options: ConvertOptions): Promise<ConvertResult> {\n const { from, to, features, silent = true, verbose = false, ...rest } = options;\n\n if (!from) {\n throw new Error(\"from is required. Please specify a source tool to convert from.\");\n }\n\n if (!to || to.length === 0) {\n throw new Error(\"to is required and must not be empty. Please specify destination tools.\");\n }\n\n const toTools = Array.from(new Set(to));\n\n if (toTools.includes(from)) {\n throw new Error(\n `Destination tools must not include the source tool '${from}'. ` +\n `Converting a tool onto itself is likely a mistake and may cause lossy round-trips.`,\n );\n }\n\n const logger = new ConsoleLogger({ verbose, silent });\n\n // NOTE: The CLI and MCP wrappers pass `[from, ...to]` as `targets` so that\n // per-target feature overrides in `rulesync.jsonc` apply to destinations too.\n // The JS API intentionally passes only `[from]` here because the public\n // contract for `convertFromTool` (issue #1557) prescribes this shape:\n // programmatic callers are expected to supply `features` explicitly when\n // they need fine-grained control, rather than relying on config-file\n // per-target maps. Defaulting `features` to `[\"*\"]` below matches the CLI's\n // \"attempt every feature both tools support\" behavior so callers who omit\n // `features` get the same effective coverage as the CLI.\n const config = await ConfigResolver.resolve({\n ...rest,\n targets: [from],\n features: features ?? [\"*\"],\n verbose,\n silent,\n });\n\n return coreConvertFromTool({ config, fromTool: from, toTools, logger });\n}\n"],"mappings":";;AAwEA,eAAsB,SAAS,UAA2B,CAAC,GAA4B;CACrF,MAAM,EAAE,SAAS,MAAM,UAAU,OAAO,GAAG,SAAS;CACpD,MAAM,SAAS,IAAI,cAAc;EAAE;EAAS;CAAO,CAAC;CAEpD,MAAM,SAAS,MAAM,eAAe,QAAQ;EAC1C,GAAG;EACH;EACA;CACF,CAAC;CAMD,MAAM,aAAa,OAAO,cAAc;CAExC,MAAM,sBAAsB,MAAM,kBAAkB,UAAU;CAE9D,IAAI,oBAAoB,YAAY,KAAA,GAClC,MAAM,IAAI,MAAM,oBAAoB,OAAO;CAG7C,OAAOA,WAAa;EAAE;EAAQ;CAAO,CAAC;AACxC;AAEA,eAAsB,eAAe,SAA+C;CAClF,MAAM,EAAE,QAAQ,UAAU,SAAS,MAAM,UAAU,OAAO,GAAG,SAAS;CACtE,MAAM,SAAS,IAAI,cAAc;EAAE;EAAS;CAAO,CAAC;CAEpD,MAAM,SAAS,MAAM,eAAe,QAAQ;EAC1C,GAAG;EACH,SAAS,CAAC,MAAM;EAChB;EACA;EACA;CACF,CAAC;CAED,OAAOC,iBAAmB;EAAE;EAAQ,MAAM;EAAQ;CAAO,CAAC;AAC5D;AAEA,eAAsB,gBAAgB,SAAiD;CACrF,MAAM,EAAE,MAAM,IAAI,UAAU,SAAS,MAAM,UAAU,OAAO,GAAG,SAAS;CAExE,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,iEAAiE;CAGnF,IAAI,CAAC,MAAM,GAAG,WAAW,GACvB,MAAM,IAAI,MAAM,yEAAyE;CAG3F,MAAM,UAAU,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;CAEtC,IAAI,QAAQ,SAAS,IAAI,GACvB,MAAM,IAAI,MACR,uDAAuD,KAAK,sFAE9D;CAGF,MAAM,SAAS,IAAI,cAAc;EAAE;EAAS;CAAO,CAAC;CAWpD,MAAM,SAAS,MAAM,eAAe,QAAQ;EAC1C,GAAG;EACH,SAAS,CAAC,IAAI;EACd,UAAU,YAAY,CAAC,GAAG;EAC1B;EACA;CACF,CAAC;CAED,OAAOC,kBAAoB;EAAE;EAAQ,UAAU;EAAM;EAAS;CAAO,CAAC;AACxE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "16.15.0",
3
+ "version": "16.17.0",
4
4
  "description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
5
5
  "keywords": [
6
6
  "ai",