@agentrules/cli 0.3.1 → 0.3.2

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.
Files changed (2) hide show
  1. package/dist/index.js +38 -13
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -35,6 +35,11 @@ const RULE_TYPE_TUPLE = [
35
35
 
36
36
  //#endregion
37
37
  //#region ../core/src/platform/config.ts
38
+ /**
39
+ * Placeholder for user's home directory in path templates.
40
+ * Consumers (e.g., CLI) are responsible for expanding this at runtime.
41
+ */
42
+ const USER_HOME_DIR_PLACEHOLDER = "{userHomeDir}";
38
43
  const PLATFORM_IDS = PLATFORM_ID_TUPLE;
39
44
  /**
40
45
  * Platform configuration including supported types and install paths.
@@ -43,7 +48,7 @@ const PLATFORMS = {
43
48
  opencode: {
44
49
  label: "OpenCode",
45
50
  platformDir: ".opencode",
46
- globalDir: "~/.config/opencode",
51
+ globalDir: "{userHomeDir}/.config/opencode",
47
52
  types: {
48
53
  instruction: {
49
54
  description: "Project instructions",
@@ -75,7 +80,7 @@ const PLATFORMS = {
75
80
  claude: {
76
81
  label: "Claude Code",
77
82
  platformDir: ".claude",
78
- globalDir: "~/.claude",
83
+ globalDir: "{userHomeDir}/.claude",
79
84
  types: {
80
85
  instruction: {
81
86
  description: "Project instructions",
@@ -102,7 +107,7 @@ const PLATFORMS = {
102
107
  cursor: {
103
108
  label: "Cursor",
104
109
  platformDir: ".cursor",
105
- globalDir: "~/.cursor",
110
+ globalDir: "{userHomeDir}/.cursor",
106
111
  types: {
107
112
  instruction: {
108
113
  description: "Project instructions",
@@ -129,7 +134,7 @@ const PLATFORMS = {
129
134
  codex: {
130
135
  label: "Codex",
131
136
  platformDir: ".codex",
132
- globalDir: "~/.codex",
137
+ globalDir: "{userHomeDir}/.codex",
133
138
  types: {
134
139
  instruction: {
135
140
  description: "Project instructions",
@@ -183,7 +188,7 @@ function getInstallPath({ platform, type, name, scope = "project" }) {
183
188
  * Returns the path relative to the platform's root directory.
184
189
  *
185
190
  * Example: For codex instruction with scope="global", returns "AGENTS.md"
186
- * (not "~/.codex/AGENTS.md")
191
+ * (not the full path with {userHomeDir})
187
192
  */
188
193
  function getRelativeInstallPath({ platform, type, name, scope = "project" }) {
189
194
  const typeConfig = getTypeConfig(platform, type);
@@ -3505,6 +3510,21 @@ const COMMON_LICENSES = [
3505
3510
  ];
3506
3511
  const licenseSchema = string().trim().min(1, "License is required").max(128, "License must be 128 characters or less");
3507
3512
  const pathSchema = string().trim().min(1);
3513
+ /**
3514
+ * Validate a bundle file path for security.
3515
+ * Rejects paths that could escape the install directory.
3516
+ *
3517
+ * @returns true if path is safe, false otherwise
3518
+ */
3519
+ function isValidBundlePath(path$1) {
3520
+ if (path$1.includes("..")) return false;
3521
+ if (path$1.startsWith("/")) return false;
3522
+ if (path$1.startsWith("~")) return false;
3523
+ if (path$1.includes("/~/") || path$1.includes("\\~\\")) return false;
3524
+ if (path$1.includes("{userHomeDir}")) return false;
3525
+ return true;
3526
+ }
3527
+ const bundlePathSchema = string().min(1).refine(isValidBundlePath, { message: "Path must be relative without traversal (no .., ~, absolute paths, or {userHomeDir})" });
3508
3528
  const ignorePatternSchema = string().trim().min(1, "Ignore pattern cannot be empty");
3509
3529
  const ignoreSchema = array(ignorePatternSchema).max(50, "Maximum 50 ignore patterns allowed");
3510
3530
  /**
@@ -3549,7 +3569,7 @@ const ruleConfigSchema = object({
3549
3569
  platforms: array(platformEntrySchema).min(1, "At least one platform is required")
3550
3570
  }).strict();
3551
3571
  const bundledFileSchema = object({
3552
- path: string().min(1),
3572
+ path: bundlePathSchema,
3553
3573
  size: number().int().nonnegative(),
3554
3574
  checksum: string().length(64),
3555
3575
  content: string()
@@ -5611,7 +5631,7 @@ function resolveInstallTarget(platform, type, name, options) {
5611
5631
  const { platformDir, globalDir } = PLATFORMS[platform];
5612
5632
  if (options.global) {
5613
5633
  if (!globalDir) throw new Error(`Platform "${platform}" does not support global installation`);
5614
- const globalRoot = resolve(expandHome(globalDir));
5634
+ const globalRoot = resolve(expandUserHomeDir(globalDir));
5615
5635
  return {
5616
5636
  root: globalRoot,
5617
5637
  mode: "global",
@@ -5623,7 +5643,7 @@ function resolveInstallTarget(platform, type, name, options) {
5623
5643
  label: `global path ${globalRoot}`
5624
5644
  };
5625
5645
  }
5626
- const projectRoot = options.directory ? resolve(expandHome(options.directory)) : process.cwd();
5646
+ const projectRoot = options.directory ? resolve(expandUserHomeDir(options.directory)) : process.cwd();
5627
5647
  const label = options.directory ? `directory ${projectRoot}` : `project root ${projectRoot}`;
5628
5648
  return {
5629
5649
  root: projectRoot,
@@ -5723,15 +5743,20 @@ function ensureWithinRoot(candidate, root) {
5723
5743
  if (candidate === root) return;
5724
5744
  if (!candidate.startsWith(normalizedRoot)) throw new Error(`Refusing to write outside of ${root}. Derived path: ${candidate}`);
5725
5745
  }
5726
- function expandHome(value) {
5727
- if (value.startsWith("~")) {
5728
- const remainder = value.slice(1);
5729
- const home = process.env.HOME || process.env.USERPROFILE || homedir();
5746
+ /**
5747
+ * Expand home directory references in a path string.
5748
+ * Handles both {userHomeDir} placeholder and ~ prefix.
5749
+ */
5750
+ function expandUserHomeDir(path$1) {
5751
+ const home = process.env.HOME || homedir();
5752
+ if (path$1.includes(USER_HOME_DIR_PLACEHOLDER)) return path$1.replace(USER_HOME_DIR_PLACEHOLDER, home);
5753
+ if (path$1.startsWith("~")) {
5754
+ const remainder = path$1.slice(1);
5730
5755
  if (!remainder) return home;
5731
5756
  if (remainder.startsWith("/") || remainder.startsWith("\\")) return `${home}${remainder}`;
5732
5757
  return `${home}/${remainder}`;
5733
5758
  }
5734
- return value;
5759
+ return path$1;
5735
5760
  }
5736
5761
 
5737
5762
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentrules/cli",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "author": "Brian Cheung <bcheung.dev@gmail.com> (https://github.com/bcheung)",
5
5
  "license": "MIT",
6
6
  "homepage": "https://agentrules.directory",
@@ -53,7 +53,7 @@
53
53
  "clean": "rm -rf node_modules dist .turbo"
54
54
  },
55
55
  "dependencies": {
56
- "@agentrules/core": "0.3.0",
56
+ "@agentrules/core": "0.3.1",
57
57
  "@clack/prompts": "^0.11.0",
58
58
  "chalk": "^5.4.1",
59
59
  "commander": "^12.1.0",