@clipboard-health/ai-rules 2.23.0 → 2.23.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @clipboard-health/ai-rules
2
2
 
3
- Pre-built AI agent rules for consistent coding standards. Uses a retrieval-based approach: generates a compressed index in `AGENTS.md` pointing to individual rule files that agents read on demand.
3
+ Pre-built AI agent rules for consistent coding standards. Uses a retrieval-based approach: generates a compressed index in `AGENTS.md` pointing to copied `.rules/` files that agents read on demand, with `.agents/` linked to package-provided agent assets.
4
4
 
5
5
  ## Table of contents
6
6
 
@@ -55,7 +55,7 @@ npm install --save-dev @clipboard-health/ai-rules
55
55
  5. Commit the generated files:
56
56
 
57
57
  ```bash
58
- git add .rules/ AGENTS.md CLAUDE.md
58
+ git add .rules/ .agents/ AGENTS.md CLAUDE.md
59
59
  git commit -m "feat: add AI coding rules"
60
60
  ```
61
61
 
@@ -96,10 +96,10 @@ npm update @clipboard-health/ai-rules
96
96
  npm install
97
97
 
98
98
  # Review the changes
99
- git diff .rules/ AGENTS.md
99
+ git diff .rules/ .agents/ AGENTS.md
100
100
 
101
101
  # Commit the updates
102
- git add .rules/ AGENTS.md CLAUDE.md
102
+ git add .rules/ .agents/ AGENTS.md CLAUDE.md
103
103
  git commit -m "chore: update AI coding rules"
104
104
  ```
105
105
 
@@ -170,10 +170,10 @@ v2 replaces the monolithic `AGENTS.md` with a retrieval-based approach. Rule fil
170
170
  npm install
171
171
  ```
172
172
 
173
- 3. Add `.rules/` to git and commit:
173
+ 3. Add `.rules/` and `.agents/` to git and commit:
174
174
 
175
175
  ```bash
176
- git add .rules/ AGENTS.md CLAUDE.md
176
+ git add .rules/ .agents/ AGENTS.md CLAUDE.md
177
177
  git commit -m "feat!: update ai-rules to v2 retrieval-based approach"
178
178
  ```
179
179
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clipboard-health/ai-rules",
3
- "version": "2.23.0",
3
+ "version": "2.23.1",
4
4
  "description": "Pre-built AI agent rules for consistent coding standards.",
5
5
  "keywords": [
6
6
  "ai",
package/scripts/sync.js CHANGED
@@ -30,10 +30,10 @@ async function sync() {
30
30
  (0, promises_1.rm)(skillsOutput, { recursive: true, force: true }),
31
31
  (0, promises_1.rm)(libraryOutput, { recursive: true, force: true }),
32
32
  ]);
33
- const [, skillsCopied, libraryCopied] = await Promise.all([
33
+ const [, skillsSyncResult, librarySyncResult] = await Promise.all([
34
34
  copyRuleFiles(ruleIds, rulesOutput),
35
- copySkillFiles(skillsOutput),
36
- copyLibraryFiles(libraryOutput),
35
+ syncAgentDirectory("skills", skillsOutput),
36
+ syncAgentDirectory("lib", libraryOutput),
37
37
  copySetupScript(),
38
38
  mergeSessionStartHook(),
39
39
  ]);
@@ -42,7 +42,10 @@ async function sync() {
42
42
  await (0, promises_1.writeFile)(node_path_1.default.join(PATHS.projectRoot, constants_1.FILES.claude), "@AGENTS.md\n", "utf8");
43
43
  console.log(`✅ @clipboard-health/ai-rules synced ${parsedArguments.profile} (${ruleIds.length} rules)`);
44
44
  await appendOverlay(PATHS.projectRoot);
45
- await formatOutputFiles(PATHS.projectRoot, { skillsCopied, libCopied: libraryCopied });
45
+ await formatOutputFiles(PATHS.projectRoot, {
46
+ skillsCopied: skillsSyncResult === "copied",
47
+ libCopied: librarySyncResult === "copied",
48
+ });
46
49
  }
47
50
  catch (error) {
48
51
  // Log error but exit gracefully to avoid breaking installs
@@ -120,33 +123,42 @@ async function copyRuleFiles(ruleIds, rulesOutput) {
120
123
  await (0, promises_1.cp)(node_path_1.default.join(PATHS.packageRoot, "rules", rulePath), destination);
121
124
  }));
122
125
  }
123
- async function copySkillFiles(skillsOutput) {
124
- const skillsSource = node_path_1.default.join(PATHS.packageRoot, "skills");
126
+ async function syncAgentDirectory(directoryName, destination) {
127
+ const source = await resolveAgentDirectorySource(directoryName);
128
+ if (!source) {
129
+ return "missing";
130
+ }
131
+ await (0, promises_1.mkdir)(node_path_1.default.dirname(destination), { recursive: true });
132
+ const relativeSource = node_path_1.default.relative(node_path_1.default.dirname(destination), source);
125
133
  try {
126
- await (0, promises_1.cp)(skillsSource, skillsOutput, { recursive: true });
127
- console.log(`📋 Synced skills to .agents/skills/`);
128
- return true;
134
+ await (0, promises_1.symlink)(relativeSource, destination, "dir");
135
+ console.log(`📋 Linked ${directoryName} to .agents/${directoryName}/`);
136
+ return "linked";
129
137
  }
130
138
  catch (error) {
131
- if (error.code === "ENOENT") {
132
- return false;
133
- }
134
- throw error;
139
+ console.warn(`⚠️ Could not symlink ${directoryName}; copying instead: ${(0, toErrorMessage_1.toErrorMessage)(error)}`);
140
+ await (0, promises_1.cp)(source, destination, { recursive: true });
141
+ console.log(`📋 Synced ${directoryName} to .agents/${directoryName}/`);
142
+ return "copied";
135
143
  }
136
144
  }
137
- async function copyLibraryFiles(libraryOutput) {
138
- const librarySource = node_path_1.default.join(PATHS.packageRoot, "lib");
139
- try {
140
- await (0, promises_1.cp)(librarySource, libraryOutput, { recursive: true });
141
- console.log(`📋 Synced lib to .agents/lib/`);
142
- return true;
145
+ async function resolveAgentDirectorySource(directoryName) {
146
+ const packageSource = node_path_1.default.join(PATHS.packageRoot, directoryName);
147
+ const sourceTreeSource = node_path_1.default.join(PATHS.projectRoot, "plugins", "core", directoryName);
148
+ // This repo runs the built sync script from dist/, but checked-in links should
149
+ // target source assets rather than ignored build output.
150
+ if (isSourceBuildPackage() && (await fileExists(sourceTreeSource))) {
151
+ return sourceTreeSource;
143
152
  }
144
- catch (error) {
145
- if (error.code === "ENOENT") {
146
- return false;
147
- }
148
- throw error;
153
+ if (await fileExists(packageSource)) {
154
+ return packageSource;
149
155
  }
156
+ return undefined;
157
+ }
158
+ function isSourceBuildPackage() {
159
+ return node_path_1.default
160
+ .normalize(PATHS.packageRoot)
161
+ .endsWith(node_path_1.default.normalize(node_path_1.default.join("dist", "packages", "ai-rules")));
150
162
  }
151
163
  async function copySetupScript() {
152
164
  const source = node_path_1.default.join(PATHS.packageRoot, "scripts", "setup.sh");
@@ -245,6 +257,11 @@ async function generateAgentsIndex(ruleIds) {
245
257
  "|------|------|-------------|",
246
258
  ...rows,
247
259
  "",
260
+ "## Agent Skills",
261
+ "",
262
+ "Agent skills are linked from `node_modules/@clipboard-health/ai-rules` into `.agents/`.",
263
+ "If a referenced skill is missing or unreadable, run `npm ci` from the repository root and retry.",
264
+ "",
248
265
  ].join("\n");
249
266
  }
250
267
  async function appendOverlay(projectRoot) {