agent-switchboard 0.1.26 → 0.1.27
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 +11 -10
- package/dist/commands/library.d.ts +1 -1
- package/dist/commands/library.js +4 -5
- package/dist/commands/library.js.map +1 -1
- package/dist/config/paths.d.ts +6 -0
- package/dist/config/paths.js +9 -0
- package/dist/config/paths.js.map +1 -1
- package/dist/config/schemas.d.ts +305 -21
- package/dist/config/schemas.js +10 -4
- package/dist/config/schemas.js.map +1 -1
- package/dist/index.js +118 -40
- package/dist/index.js.map +1 -1
- package/dist/library/sources.d.ts +72 -0
- package/dist/library/sources.js +279 -0
- package/dist/library/sources.js.map +1 -0
- package/dist/rules/agents.d.ts +4 -4
- package/dist/rules/agents.js +10 -4
- package/dist/rules/agents.js.map +1 -1
- package/dist/rules/distribution.js +46 -110
- package/dist/rules/distribution.js.map +1 -1
- package/dist/rules/library.d.ts +1 -1
- package/dist/rules/library.js +4 -5
- package/dist/rules/library.js.map +1 -1
- package/dist/skills/library.d.ts +1 -1
- package/dist/skills/library.js +4 -5
- package/dist/skills/library.js.map +1 -1
- package/dist/subagents/library.d.ts +1 -1
- package/dist/subagents/library.js +4 -5
- package/dist/subagents/library.js.map +1 -1
- package/package.json +1 -1
- package/dist/library/subscriptions.d.ts +0 -42
- package/dist/library/subscriptions.js +0 -116
- package/dist/library/subscriptions.js.map +0 -1
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Library source management utilities.
|
|
3
|
+
* Handles adding, removing, and listing external library sources.
|
|
4
|
+
* Supports both local directory paths and remote git repository URLs.
|
|
5
|
+
*/
|
|
6
|
+
import { execFileSync } from 'node:child_process';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { updateConfigLayer } from '../config/layered-config.js';
|
|
10
|
+
import { getSourceCacheDir } from '../config/paths.js';
|
|
11
|
+
import { loadSwitchboardConfig } from '../config/switchboard-config.js';
|
|
12
|
+
// ── Git utilities ──────────────────────────────────────────────────
|
|
13
|
+
function runGit(args, options) {
|
|
14
|
+
try {
|
|
15
|
+
return execFileSync('git', args, {
|
|
16
|
+
...options,
|
|
17
|
+
stdio: 'pipe',
|
|
18
|
+
encoding: 'utf-8',
|
|
19
|
+
timeout: 120_000,
|
|
20
|
+
}).trim();
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
const execError = error;
|
|
24
|
+
const stderr = typeof execError.stderr === 'string'
|
|
25
|
+
? execError.stderr.trim()
|
|
26
|
+
: (execError.stderr?.toString().trim() ?? '');
|
|
27
|
+
throw new Error(`git ${args[0]} failed: ${stderr || (error instanceof Error ? error.message : String(error))}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function ensureGitAvailable() {
|
|
31
|
+
try {
|
|
32
|
+
runGit(['--version']);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new Error('git is not available. Install git to use remote sources.');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function gitClone(url, targetDir, ref) {
|
|
39
|
+
if (fs.existsSync(targetDir)) {
|
|
40
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
41
|
+
}
|
|
42
|
+
fs.mkdirSync(path.dirname(targetDir), { recursive: true });
|
|
43
|
+
const args = ['clone', '--depth', '1'];
|
|
44
|
+
if (ref)
|
|
45
|
+
args.push('--branch', ref);
|
|
46
|
+
args.push(url, targetDir);
|
|
47
|
+
runGit(args);
|
|
48
|
+
}
|
|
49
|
+
function gitPull(repoDir) {
|
|
50
|
+
runGit(['pull'], { cwd: repoDir });
|
|
51
|
+
}
|
|
52
|
+
// ── URL detection and parsing ──────────────────────────────────────
|
|
53
|
+
export function isGitUrl(source) {
|
|
54
|
+
return /^(https?:\/\/|git@|ssh:\/\/|git:\/\/)/.test(source);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Parse a GitHub URL into clone URL + optional ref and subdir.
|
|
58
|
+
* Supported:
|
|
59
|
+
* https://github.com/org/repo
|
|
60
|
+
* https://github.com/org/repo/tree/branch
|
|
61
|
+
* https://github.com/org/repo/tree/branch/sub/dir
|
|
62
|
+
* Non-GitHub git URLs pass through unchanged.
|
|
63
|
+
*/
|
|
64
|
+
export function parseGitUrl(input) {
|
|
65
|
+
const treeMatch = input.match(/^(https:\/\/github\.com\/[^/]+\/[^/]+?)(?:\.git)?\/tree\/([^/]+)(?:\/(.+))?$/);
|
|
66
|
+
if (treeMatch) {
|
|
67
|
+
const result = {
|
|
68
|
+
url: `${treeMatch[1]}.git`,
|
|
69
|
+
ref: treeMatch[2],
|
|
70
|
+
};
|
|
71
|
+
if (treeMatch[3])
|
|
72
|
+
result.subdir = treeMatch[3];
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
const ghRepo = input.match(/^(https:\/\/github\.com\/[^/]+\/[^/]+?)(?:\.git)?\/?$/);
|
|
76
|
+
if (ghRepo) {
|
|
77
|
+
return { url: `${ghRepo[1]}.git` };
|
|
78
|
+
}
|
|
79
|
+
return { url: input };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Infer a namespace from a git URL or local path.
|
|
83
|
+
* Examples:
|
|
84
|
+
* https://github.com/org/my-repo.git → "my-repo"
|
|
85
|
+
* https://github.com/org/repo/tree/main/sub → "repo"
|
|
86
|
+
* git@github.com:org/repo.git → "repo"
|
|
87
|
+
* /path/to/team-library → "team-library"
|
|
88
|
+
*/
|
|
89
|
+
export function inferSourceName(location) {
|
|
90
|
+
if (isGitUrl(location)) {
|
|
91
|
+
const { url } = parseGitUrl(location);
|
|
92
|
+
const httpsMatch = url.match(/\/([^/]+?)(?:\.git)?$/);
|
|
93
|
+
if (httpsMatch)
|
|
94
|
+
return httpsMatch[1];
|
|
95
|
+
const sshMatch = url.match(/:([^/]+?)(?:\.git)?$/);
|
|
96
|
+
if (sshMatch)
|
|
97
|
+
return sshMatch[1];
|
|
98
|
+
}
|
|
99
|
+
return path.basename(path.resolve(location));
|
|
100
|
+
}
|
|
101
|
+
// ── Config access helpers ──────────────────────────────────────────
|
|
102
|
+
function getRawSources() {
|
|
103
|
+
const config = loadSwitchboardConfig();
|
|
104
|
+
return config.library.sources;
|
|
105
|
+
}
|
|
106
|
+
function resolveEffectivePath(namespace, value) {
|
|
107
|
+
if (typeof value === 'string')
|
|
108
|
+
return value;
|
|
109
|
+
let effectivePath = getSourceCacheDir(namespace);
|
|
110
|
+
if (value.subdir)
|
|
111
|
+
effectivePath = path.join(effectivePath, value.subdir);
|
|
112
|
+
return effectivePath;
|
|
113
|
+
}
|
|
114
|
+
// ── Validation helpers ─────────────────────────────────────────────
|
|
115
|
+
function validateNamespace(namespace) {
|
|
116
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(namespace)) {
|
|
117
|
+
throw new Error(`Invalid namespace "${namespace}". Use only letters, numbers, hyphens, and underscores.`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function ensureNamespaceAvailable(namespace) {
|
|
121
|
+
if (hasSource(namespace)) {
|
|
122
|
+
throw new Error(`Source "${namespace}" already exists. Use a different name or remove it first.`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// ── Public API ─────────────────────────────────────────────────────
|
|
126
|
+
export function getSources() {
|
|
127
|
+
const raw = getRawSources();
|
|
128
|
+
return Object.entries(raw).map(([namespace, value]) => {
|
|
129
|
+
const effectivePath = resolveEffectivePath(namespace, value);
|
|
130
|
+
if (typeof value === 'string') {
|
|
131
|
+
return { namespace, path: effectivePath };
|
|
132
|
+
}
|
|
133
|
+
return { namespace, path: effectivePath, remote: value };
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get sources as namespace -> effective local path.
|
|
138
|
+
* Remote sources are transparently resolved to their cache directory.
|
|
139
|
+
*/
|
|
140
|
+
export function getSourcesRecord() {
|
|
141
|
+
const raw = getRawSources();
|
|
142
|
+
const result = {};
|
|
143
|
+
for (const [namespace, value] of Object.entries(raw)) {
|
|
144
|
+
result[namespace] = resolveEffectivePath(namespace, value);
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
export function hasSource(namespace) {
|
|
149
|
+
return namespace in getRawSources();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Add a local directory source.
|
|
153
|
+
*/
|
|
154
|
+
export function addLocalSource(namespace, libraryPath) {
|
|
155
|
+
const resolvedPath = path.resolve(libraryPath);
|
|
156
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
157
|
+
throw new Error(`Path does not exist: ${resolvedPath}`);
|
|
158
|
+
}
|
|
159
|
+
if (!fs.statSync(resolvedPath).isDirectory()) {
|
|
160
|
+
throw new Error(`Path is not a directory: ${resolvedPath}`);
|
|
161
|
+
}
|
|
162
|
+
validateNamespace(namespace);
|
|
163
|
+
ensureNamespaceAvailable(namespace);
|
|
164
|
+
updateConfigLayer((layer) => ({
|
|
165
|
+
...layer,
|
|
166
|
+
library: {
|
|
167
|
+
...layer.library,
|
|
168
|
+
sources: {
|
|
169
|
+
...(layer.library?.sources ?? {}),
|
|
170
|
+
[namespace]: resolvedPath,
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Add a remote git source. Clones the repo into the local cache.
|
|
177
|
+
*/
|
|
178
|
+
export function addRemoteSource(namespace, remote) {
|
|
179
|
+
validateNamespace(namespace);
|
|
180
|
+
ensureNamespaceAvailable(namespace);
|
|
181
|
+
ensureGitAvailable();
|
|
182
|
+
const cacheDir = getSourceCacheDir(namespace);
|
|
183
|
+
gitClone(remote.url, cacheDir, remote.ref);
|
|
184
|
+
const configValue = { url: remote.url };
|
|
185
|
+
if (remote.ref)
|
|
186
|
+
configValue.ref = remote.ref;
|
|
187
|
+
if (remote.subdir)
|
|
188
|
+
configValue.subdir = remote.subdir;
|
|
189
|
+
updateConfigLayer((layer) => ({
|
|
190
|
+
...layer,
|
|
191
|
+
library: {
|
|
192
|
+
...layer.library,
|
|
193
|
+
sources: {
|
|
194
|
+
...(layer.library?.sources ?? {}),
|
|
195
|
+
[namespace]: configValue,
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Remove a source and clean up its cache directory if remote.
|
|
202
|
+
*/
|
|
203
|
+
export function removeSource(namespace) {
|
|
204
|
+
const raw = getRawSources();
|
|
205
|
+
if (!(namespace in raw)) {
|
|
206
|
+
throw new Error(`Source "${namespace}" not found.`);
|
|
207
|
+
}
|
|
208
|
+
const value = raw[namespace];
|
|
209
|
+
updateConfigLayer((layer) => {
|
|
210
|
+
const newSources = { ...(layer.library?.sources ?? {}) };
|
|
211
|
+
delete newSources[namespace];
|
|
212
|
+
return {
|
|
213
|
+
...layer,
|
|
214
|
+
library: {
|
|
215
|
+
...layer.library,
|
|
216
|
+
sources: newSources,
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
});
|
|
220
|
+
if (typeof value !== 'string') {
|
|
221
|
+
const cacheDir = getSourceCacheDir(namespace);
|
|
222
|
+
if (fs.existsSync(cacheDir)) {
|
|
223
|
+
fs.rmSync(cacheDir, { recursive: true, force: true });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Validate a local path has expected library structure.
|
|
229
|
+
*/
|
|
230
|
+
export function validateSourcePath(libraryPath) {
|
|
231
|
+
const resolvedPath = path.resolve(libraryPath);
|
|
232
|
+
const libraryTypes = ['rules', 'commands', 'subagents', 'skills'];
|
|
233
|
+
const found = [];
|
|
234
|
+
const missing = [];
|
|
235
|
+
for (const type of libraryTypes) {
|
|
236
|
+
const typePath = path.join(resolvedPath, type);
|
|
237
|
+
if (fs.existsSync(typePath) && fs.statSync(typePath).isDirectory()) {
|
|
238
|
+
found.push(type);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
missing.push(type);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return { valid: found.length > 0, found, missing };
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Pull latest changes for all remote sources.
|
|
248
|
+
* Re-clones if the cache directory is missing or corrupted.
|
|
249
|
+
*/
|
|
250
|
+
export function updateRemoteSources() {
|
|
251
|
+
const raw = getRawSources();
|
|
252
|
+
const results = [];
|
|
253
|
+
for (const [namespace, value] of Object.entries(raw)) {
|
|
254
|
+
if (typeof value === 'string')
|
|
255
|
+
continue;
|
|
256
|
+
const cacheDir = getSourceCacheDir(namespace);
|
|
257
|
+
const gitDir = path.join(cacheDir, '.git');
|
|
258
|
+
try {
|
|
259
|
+
ensureGitAvailable();
|
|
260
|
+
if (!fs.existsSync(gitDir)) {
|
|
261
|
+
gitClone(value.url, cacheDir, value.ref);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
gitPull(cacheDir);
|
|
265
|
+
}
|
|
266
|
+
results.push({ namespace, url: value.url, status: 'updated' });
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
results.push({
|
|
270
|
+
namespace,
|
|
271
|
+
url: value.url,
|
|
272
|
+
status: 'error',
|
|
273
|
+
error: err instanceof Error ? err.message : String(err),
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return results;
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sources.js","sourceRoot":"","sources":["../../src/library/sources.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAexE,sEAAsE;AAEtE,SAAS,MAAM,CAAC,IAAc,EAAE,OAA0B;IACxD,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE;YAC/B,GAAG,OAAO;YACV,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,OAAO;SACjB,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,KAAqC,CAAC;QACxD,MAAM,MAAM,GACV,OAAO,SAAS,CAAC,MAAM,KAAK,QAAQ;YAClC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE;YACzB,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,IAAI,KAAK,CACb,OAAO,IAAI,CAAC,CAAC,CAAC,YAAY,MAAM,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAC/F,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB;IACzB,IAAI,CAAC;QACH,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW,EAAE,SAAiB,EAAE,GAAY;IAC5D,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3D,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;IACvC,IAAI,GAAG;QAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC1B,MAAM,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,OAAO,CAAC,OAAe;IAC9B,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,sEAAsE;AAEtE,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,OAAO,uCAAuC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAC3B,8EAA8E,CAC/E,CAAC;IACF,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,MAAM,GAAmD;YAC7D,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM;YAC1B,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC;SAClB,CAAC;QACF,IAAI,SAAS,CAAC,CAAC,CAAC;YAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC/C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACpF,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACrC,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;AACxB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvB,MAAM,EAAE,GAAG,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACtD,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACnD,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,sEAAsE;AAEtE,SAAS,aAAa;IACpB,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;IACvC,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;AAChC,CAAC;AAED,SAAS,oBAAoB,CAAC,SAAiB,EAAE,KAAkB;IACjE,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,aAAa,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACjD,IAAI,KAAK,CAAC,MAAM;QAAE,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzE,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,sEAAsE;AAEtE,SAAS,iBAAiB,CAAC,SAAiB;IAC1C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,sBAAsB,SAAS,yDAAyD,CACzF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAiB;IACjD,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,WAAW,SAAS,4DAA4D,CACjF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,sEAAsE;AAEtE,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,EAAE;QACpD,MAAM,aAAa,GAAG,oBAAoB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC7D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;QAC5C,CAAC;QACD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,MAAM,CAAC,SAAS,CAAC,GAAG,oBAAoB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,SAAiB;IACzC,OAAO,SAAS,IAAI,aAAa,EAAE,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,WAAmB;IACnE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAE/C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,wBAAwB,YAAY,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,4BAA4B,YAAY,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC7B,wBAAwB,CAAC,SAAS,CAAC,CAAC;IAEpC,iBAAiB,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5B,GAAG,KAAK;QACR,OAAO,EAAE;YACP,GAAG,KAAK,CAAC,OAAO;YAChB,OAAO,EAAE;gBACP,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;gBACjC,CAAC,SAAS,CAAC,EAAE,YAAY;aAC1B;SACF;KACF,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiB,EAAE,MAAoB;IACrE,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC7B,wBAAwB,CAAC,SAAS,CAAC,CAAC;IACpC,kBAAkB,EAAE,CAAC;IAErB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC9C,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAE3C,MAAM,WAAW,GAAiB,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;IACtD,IAAI,MAAM,CAAC,GAAG;QAAE,WAAW,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;IAC7C,IAAI,MAAM,CAAC,MAAM;QAAE,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAEtD,iBAAiB,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5B,GAAG,KAAK;QACR,OAAO,EAAE;YACP,GAAG,KAAK,CAAC,OAAO;YAChB,OAAO,EAAE;gBACP,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;gBACjC,CAAC,SAAS,CAAC,EAAE,WAAW;aACzB;SACF;KACF,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,cAAc,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;IAE7B,iBAAiB,CAAC,CAAC,KAAK,EAAE,EAAE;QAC1B,MAAM,UAAU,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;QACzD,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC;QAC7B,OAAO;YACL,GAAG,KAAK;YACR,OAAO,EAAE;gBACP,GAAG,KAAK,CAAC,OAAO;gBAChB,OAAO,EAAE,UAAU;aACpB;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IAKpD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IAClE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAC/C,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACnE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAyB,EAAE,CAAC;IAEzC,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAS;QAExC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAE3C,IAAI,CAAC;YACH,kBAAkB,EAAE,CAAC;YACrB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3B,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;YAC3C,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,QAAQ,CAAC,CAAC;YACpB,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC;gBACX,SAAS;gBACT,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/rules/agents.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/** Agents that receive a single composed rules file (CLAUDE.md / AGENTS.md) */
|
|
2
|
-
export declare const RULE_SUPPORTED_AGENTS: readonly ["claude-code", "codex", "gemini", "opencode"];
|
|
3
|
-
/** Agents that receive individual
|
|
4
|
-
export declare const RULE_PER_FILE_AGENTS: readonly [
|
|
1
|
+
/** Agents that receive a single composed rules file (CLAUDE.md / AGENTS.md / .mdc) */
|
|
2
|
+
export declare const RULE_SUPPORTED_AGENTS: readonly ["claude-code", "codex", "cursor", "gemini", "opencode"];
|
|
3
|
+
/** Agents that receive individual per-rule files */
|
|
4
|
+
export declare const RULE_PER_FILE_AGENTS: readonly [];
|
|
5
5
|
export declare const RULE_INDIRECT_AGENTS: readonly [];
|
|
6
6
|
export declare const RULE_UNSUPPORTED_AGENTS: readonly ["claude-desktop"];
|
|
7
7
|
export type RuleSupportedAgent = (typeof RULE_SUPPORTED_AGENTS)[number];
|
package/dist/rules/agents.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
/** Agents that receive a single composed rules file (CLAUDE.md / AGENTS.md) */
|
|
2
|
-
export const RULE_SUPPORTED_AGENTS = [
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/** Agents that receive a single composed rules file (CLAUDE.md / AGENTS.md / .mdc) */
|
|
2
|
+
export const RULE_SUPPORTED_AGENTS = [
|
|
3
|
+
'claude-code',
|
|
4
|
+
'codex',
|
|
5
|
+
'cursor',
|
|
6
|
+
'gemini',
|
|
7
|
+
'opencode',
|
|
8
|
+
];
|
|
9
|
+
/** Agents that receive individual per-rule files */
|
|
10
|
+
export const RULE_PER_FILE_AGENTS = [];
|
|
5
11
|
export const RULE_INDIRECT_AGENTS = [];
|
|
6
12
|
export const RULE_UNSUPPORTED_AGENTS = ['claude-desktop'];
|
|
7
13
|
//# sourceMappingURL=agents.js.map
|
package/dist/rules/agents.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/rules/agents.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/rules/agents.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,aAAa;IACb,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,UAAU;CACF,CAAC;AAEX,oDAAoD;AACpD,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAW,CAAC;AAEhD,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAW,CAAC;AAEhD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,gBAAgB,CAAU,CAAC"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
1
|
import fs from 'node:fs';
|
|
3
2
|
import path from 'node:path';
|
|
4
|
-
import { resolveAgentSectionConfig } from '../config/agent-config.js';
|
|
5
3
|
import { getAgentsHome, getClaudeDir, getCodexDir, getCursorDir, getGeminiDir, getOpencodePath, getProjectCursorDir, } from '../config/paths.js';
|
|
6
4
|
import { RULE_INDIRECT_AGENTS, RULE_PER_FILE_AGENTS, RULE_SUPPORTED_AGENTS, RULE_UNSUPPORTED_AGENTS, } from './agents.js';
|
|
7
5
|
import { composeActiveRulesForAgent } from './composer.js';
|
|
@@ -29,6 +27,11 @@ function resolveRuleFile(agent, scope) {
|
|
|
29
27
|
return path.join(path.resolve(projectRoot), 'AGENTS.md');
|
|
30
28
|
}
|
|
31
29
|
return path.join(getGeminiDir(), 'AGENTS.md');
|
|
30
|
+
case 'cursor':
|
|
31
|
+
if (projectRoot && projectRoot.length > 0) {
|
|
32
|
+
return path.join(getProjectCursorDir(projectRoot), 'rules', 'asb-rules.mdc');
|
|
33
|
+
}
|
|
34
|
+
return path.join(getCursorDir(), 'rules', 'asb-rules.mdc');
|
|
32
35
|
case 'opencode':
|
|
33
36
|
// OpenCode supports project-level AGENTS.md at repository root; otherwise use global.
|
|
34
37
|
if (projectRoot && projectRoot.length > 0) {
|
|
@@ -45,6 +48,41 @@ function ensureDirectory(filePath) {
|
|
|
45
48
|
fs.mkdirSync(dir, { recursive: true });
|
|
46
49
|
}
|
|
47
50
|
}
|
|
51
|
+
function wrapMdcFrontmatter(body) {
|
|
52
|
+
const lines = ['---', 'description: Agent Switchboard Rules', 'alwaysApply: true', '---', ''];
|
|
53
|
+
if (body.length > 0) {
|
|
54
|
+
lines.push(body);
|
|
55
|
+
}
|
|
56
|
+
return lines.join('\n');
|
|
57
|
+
}
|
|
58
|
+
const CURSOR_SINGLE_FILE = 'asb-rules.mdc';
|
|
59
|
+
/**
|
|
60
|
+
* Remove legacy per-rule .mdc files left by the old Cursor distribution scheme.
|
|
61
|
+
* Only deletes files whose basename (minus .mdc) matches a known rule library ID,
|
|
62
|
+
* leaving user-created .mdc files and the new single-file untouched.
|
|
63
|
+
*/
|
|
64
|
+
function cleanupLegacyCursorMdcFiles(scope) {
|
|
65
|
+
const projectRoot = scope?.project?.trim();
|
|
66
|
+
const targetDir = projectRoot && projectRoot.length > 0
|
|
67
|
+
? path.join(getProjectCursorDir(projectRoot), 'rules')
|
|
68
|
+
: path.join(getCursorDir(), 'rules');
|
|
69
|
+
if (!fs.existsSync(targetDir))
|
|
70
|
+
return;
|
|
71
|
+
const libraryIds = new Set(loadRuleLibrary().map((r) => r.id));
|
|
72
|
+
for (const file of fs.readdirSync(targetDir)) {
|
|
73
|
+
if (!file.endsWith('.mdc') || file === CURSOR_SINGLE_FILE)
|
|
74
|
+
continue;
|
|
75
|
+
const fileId = file.slice(0, -4);
|
|
76
|
+
if (libraryIds.has(fileId)) {
|
|
77
|
+
try {
|
|
78
|
+
fs.unlinkSync(path.join(targetDir, file));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// best-effort
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
48
86
|
export function distributeRules(_composed, options, scope) {
|
|
49
87
|
const results = [];
|
|
50
88
|
const timestamp = new Date().toISOString();
|
|
@@ -59,6 +97,7 @@ export function distributeRules(_composed, options, scope) {
|
|
|
59
97
|
firstComposed = document;
|
|
60
98
|
}
|
|
61
99
|
const filePath = resolveRuleFile(agent, scope);
|
|
100
|
+
const finalContent = agent === 'cursor' ? wrapMdcFrontmatter(document.content) : document.content;
|
|
62
101
|
let existingContent = null;
|
|
63
102
|
try {
|
|
64
103
|
if (fs.existsSync(filePath)) {
|
|
@@ -69,7 +108,7 @@ export function distributeRules(_composed, options, scope) {
|
|
|
69
108
|
existingContent = null;
|
|
70
109
|
}
|
|
71
110
|
const hadExistingFile = existingContent !== null;
|
|
72
|
-
const contentMatches = existingContent !== null && existingContent ===
|
|
111
|
+
const contentMatches = existingContent !== null && existingContent === finalContent;
|
|
73
112
|
if (!forceRewrite && contentMatches) {
|
|
74
113
|
results.push({
|
|
75
114
|
agent,
|
|
@@ -83,7 +122,7 @@ export function distributeRules(_composed, options, scope) {
|
|
|
83
122
|
const reason = hadExistingFile ? (contentMatches ? 'refreshed' : 'updated') : 'created';
|
|
84
123
|
try {
|
|
85
124
|
ensureDirectory(filePath);
|
|
86
|
-
fs.writeFileSync(filePath,
|
|
125
|
+
fs.writeFileSync(filePath, finalContent, 'utf-8');
|
|
87
126
|
agentSyncUpdates.set(agent, { hash: document.hash, updatedAt: timestamp });
|
|
88
127
|
results.push({ agent, filePath, status: 'written', reason });
|
|
89
128
|
}
|
|
@@ -92,12 +131,9 @@ export function distributeRules(_composed, options, scope) {
|
|
|
92
131
|
results.push({ agent, filePath, status: 'error', error: message });
|
|
93
132
|
}
|
|
94
133
|
}
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
for (const [agent, update] of perFileResults.syncUpdates.entries()) {
|
|
99
|
-
agentSyncUpdates.set(agent, update);
|
|
100
|
-
}
|
|
134
|
+
// Clean up legacy per-rule .mdc files from the old Cursor distribution scheme.
|
|
135
|
+
// The new approach writes a single asb-rules.mdc; old <ruleId>.mdc files are orphans.
|
|
136
|
+
cleanupLegacyCursorMdcFiles(scope);
|
|
101
137
|
if (agentSyncUpdates.size > 0) {
|
|
102
138
|
updateRuleState((current) => {
|
|
103
139
|
const agentSync = { ...current.agentSync };
|
|
@@ -116,106 +152,6 @@ export function distributeRules(_composed, options, scope) {
|
|
|
116
152
|
};
|
|
117
153
|
}
|
|
118
154
|
// ---------------------------------------------------------------------------
|
|
119
|
-
// Cursor .mdc per-file distribution
|
|
120
|
-
// ---------------------------------------------------------------------------
|
|
121
|
-
function resolveCursorRulesDir(scope) {
|
|
122
|
-
const projectRoot = scope?.project?.trim();
|
|
123
|
-
if (projectRoot && projectRoot.length > 0) {
|
|
124
|
-
return path.join(getProjectCursorDir(projectRoot), 'rules');
|
|
125
|
-
}
|
|
126
|
-
return path.join(getCursorDir(), 'rules');
|
|
127
|
-
}
|
|
128
|
-
function renderMdcRule(rule) {
|
|
129
|
-
const extras = rule.metadata.extras;
|
|
130
|
-
const cursorExtras = (extras?.cursor ?? {});
|
|
131
|
-
const description = typeof cursorExtras.description === 'string'
|
|
132
|
-
? cursorExtras.description
|
|
133
|
-
: (rule.metadata.description ?? rule.metadata.title ?? rule.id);
|
|
134
|
-
const alwaysApply = typeof cursorExtras.alwaysApply === 'boolean' ? cursorExtras.alwaysApply : true;
|
|
135
|
-
const lines = ['---', `description: ${description}`, `alwaysApply: ${alwaysApply}`];
|
|
136
|
-
if (typeof cursorExtras.globs === 'string' && cursorExtras.globs.length > 0) {
|
|
137
|
-
lines.push(`globs: ${cursorExtras.globs}`);
|
|
138
|
-
}
|
|
139
|
-
lines.push('---', '');
|
|
140
|
-
const body = rule.content.replace(/\r\n/g, '\n').replace(/\s+$/u, '');
|
|
141
|
-
if (body.length > 0) {
|
|
142
|
-
lines.push(body);
|
|
143
|
-
lines.push('');
|
|
144
|
-
}
|
|
145
|
-
return lines.join('\n');
|
|
146
|
-
}
|
|
147
|
-
function distributeCursorRules(forceRewrite, scope) {
|
|
148
|
-
const results = [];
|
|
149
|
-
const syncUpdates = new Map();
|
|
150
|
-
const timestamp = new Date().toISOString();
|
|
151
|
-
for (const agent of RULE_PER_FILE_AGENTS) {
|
|
152
|
-
const agentConfig = resolveAgentSectionConfig('rules', agent, scope);
|
|
153
|
-
const activeIds = new Set(agentConfig.active);
|
|
154
|
-
const rules = loadRuleLibrary();
|
|
155
|
-
const ruleMap = new Map(rules.map((r) => [r.id, r]));
|
|
156
|
-
const libraryIds = new Set(rules.map((r) => r.id));
|
|
157
|
-
const targetDir = resolveCursorRulesDir(scope);
|
|
158
|
-
const hashes = [];
|
|
159
|
-
let hadError = false;
|
|
160
|
-
for (const id of agentConfig.active) {
|
|
161
|
-
const rule = ruleMap.get(id);
|
|
162
|
-
if (!rule)
|
|
163
|
-
continue;
|
|
164
|
-
const filePath = path.join(targetDir, `${id}.mdc`);
|
|
165
|
-
const content = renderMdcRule(rule);
|
|
166
|
-
hashes.push(createHash('sha256').update(content).digest('hex'));
|
|
167
|
-
let existing = null;
|
|
168
|
-
try {
|
|
169
|
-
if (fs.existsSync(filePath))
|
|
170
|
-
existing = fs.readFileSync(filePath, 'utf-8');
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
existing = null;
|
|
174
|
-
}
|
|
175
|
-
if (!forceRewrite && existing === content) {
|
|
176
|
-
results.push({ agent, filePath, status: 'skipped', reason: 'up-to-date' });
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
try {
|
|
180
|
-
ensureDirectory(filePath);
|
|
181
|
-
fs.writeFileSync(filePath, content, 'utf-8');
|
|
182
|
-
results.push({
|
|
183
|
-
agent,
|
|
184
|
-
filePath,
|
|
185
|
-
status: 'written',
|
|
186
|
-
reason: existing !== null ? 'updated' : 'created',
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
hadError = true;
|
|
191
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
192
|
-
results.push({ agent, filePath, status: 'error', error: message });
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
// Cleanup orphan .mdc files: files in target dir whose ID is in the library but not active
|
|
196
|
-
if (fs.existsSync(targetDir)) {
|
|
197
|
-
for (const file of fs.readdirSync(targetDir)) {
|
|
198
|
-
if (!file.endsWith('.mdc'))
|
|
199
|
-
continue;
|
|
200
|
-
const fileId = file.slice(0, -4);
|
|
201
|
-
if (libraryIds.has(fileId) && !activeIds.has(fileId)) {
|
|
202
|
-
try {
|
|
203
|
-
fs.unlinkSync(path.join(targetDir, file));
|
|
204
|
-
}
|
|
205
|
-
catch {
|
|
206
|
-
// best-effort cleanup
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
if (!hadError) {
|
|
212
|
-
const combinedHash = createHash('sha256').update(hashes.join(':')).digest('hex');
|
|
213
|
-
syncUpdates.set(agent, { hash: combinedHash, updatedAt: timestamp });
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return { results, syncUpdates };
|
|
217
|
-
}
|
|
218
|
-
// ---------------------------------------------------------------------------
|
|
219
155
|
// Public helpers
|
|
220
156
|
// ---------------------------------------------------------------------------
|
|
221
157
|
export function listUnsupportedAgents() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"distribution.js","sourceRoot":"","sources":["../../src/rules/distribution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"distribution.js","sourceRoot":"","sources":["../../src/rules/distribution.ts"],"names":[],"mappings":"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"}
|
package/dist/rules/library.d.ts
CHANGED
|
@@ -10,6 +10,6 @@ export interface RuleSnippet {
|
|
|
10
10
|
}
|
|
11
11
|
export declare function ensureRulesDirectory(): string;
|
|
12
12
|
/**
|
|
13
|
-
* Load all rules from default library and
|
|
13
|
+
* Load all rules from default library and external sources
|
|
14
14
|
*/
|
|
15
15
|
export declare function loadRuleLibrary(): RuleSnippet[];
|
package/dist/rules/library.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { getRulesDir } from '../config/paths.js';
|
|
4
|
-
import {
|
|
4
|
+
import { getSourcesRecord } from '../library/sources.js';
|
|
5
5
|
import { parseRuleMarkdown } from './parser.js';
|
|
6
6
|
function isMarkdownFile(fileName) {
|
|
7
7
|
const extension = path.extname(fileName).toLowerCase();
|
|
@@ -59,16 +59,15 @@ function loadRulesFromDirectory(directory, namespace) {
|
|
|
59
59
|
return rules;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
* Load all rules from default library and
|
|
62
|
+
* Load all rules from default library and external sources
|
|
63
63
|
*/
|
|
64
64
|
export function loadRuleLibrary() {
|
|
65
65
|
const rules = [];
|
|
66
66
|
// Load from default library (no namespace)
|
|
67
67
|
const defaultDir = ensureRulesDirectory();
|
|
68
68
|
rules.push(...loadRulesFromDirectory(defaultDir));
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
for (const [namespace, basePath] of Object.entries(subscriptions)) {
|
|
69
|
+
const sources = getSourcesRecord();
|
|
70
|
+
for (const [namespace, basePath] of Object.entries(sources)) {
|
|
72
71
|
const rulesDir = path.join(basePath, 'rules');
|
|
73
72
|
rules.push(...loadRulesFromDirectory(rulesDir, namespace));
|
|
74
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"library.js","sourceRoot":"","sources":["../../src/rules/library.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"library.js","sourceRoot":"","sources":["../../src/rules/library.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAahD,SAAS,cAAc,CAAC,QAAgB;IACtC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACvD,OAAO,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,WAAW,CAAC;AAC1D,CAAC;AAED,SAAS,QAAQ,CAAC,QAAgB;IAChC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,MAAM,SAAS,GAAG,WAAW,EAAE,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,SAAS,sBAAsB,CAAC,SAAiB,EAAE,SAAkB;IACnE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,SAAS;QAC9B,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QAE1C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAE1D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACpC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;YAEzD,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE;gBACF,MAAM;gBACN,SAAS;gBACT,MAAM,EAAE,SAAS;gBACjB,QAAQ,EAAE,YAAY;gBACtB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,iCAAiC,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACpF,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,2CAA2C;IAC3C,MAAM,UAAU,GAAG,oBAAoB,EAAE,CAAC;IAC1C,KAAK,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC,CAAC;IAElD,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC9C,KAAK,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC;AACf,CAAC"}
|