@maz-ui/node 5.2.0 → 5.3.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/README.md +1 -1
- package/dist/agents.d.mts +198 -0
- package/dist/agents.d.ts +198 -0
- package/dist/agents.mjs +5 -0
- package/dist/index.d.mts +3 -149
- package/dist/index.d.ts +3 -149
- package/dist/index.mjs +22 -480
- package/dist/shared/node.rmAtZA9U.mjs +635 -0
- package/package.json +12 -6
package/dist/index.mjs
CHANGED
|
@@ -3,10 +3,11 @@ import process$1 from 'node:process';
|
|
|
3
3
|
import { blueBright } from 'colorette';
|
|
4
4
|
import { createConsola } from 'consola';
|
|
5
5
|
import figlet from 'figlet';
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
6
|
+
export { A as AGENTS_MD_BEGIN, a as AGENTS_MD_END, b as AGENT_TARGETS, D as DEFAULT_MCP_SERVER, M as MANAGED_MARKER, c as MAZ_UI_AGENTS_TOOL, d as MCP_SERVER_NAME, e as compareVersions, f as detectAgentTargets, g as detectPackageManager, h as findInstalledPackage, i as findProjectPackage, j as findWorkspaceDirs, k as findWorkspacesUsing, l as installsMcpPackage, m as isEditedManagedContent, n as mcpServerCommand, r as readAgentDocs, o as readManagedVersion, p as readPackageVersion, q as readWorkspacePatterns, s as resolveRulePaths, t as setupAgents, w as writeFileAtomic } from './shared/node.rmAtZA9U.mjs';
|
|
7
|
+
import 'node:crypto';
|
|
8
|
+
import 'node:fs';
|
|
9
|
+
import 'node:path';
|
|
10
|
+
import 'jsonc-parser';
|
|
10
11
|
|
|
11
12
|
const LogLevelMap = {
|
|
12
13
|
silent: Number.NEGATIVE_INFINITY,
|
|
@@ -65,9 +66,18 @@ const keepEnds = (value) => value.length < MIN_LENGTH_TO_REVEAL ? MASK : `${valu
|
|
|
65
66
|
const keepPrefix = (_match, prefix, value) => `${prefix}${keepEnds(value)}`;
|
|
66
67
|
const REDACTION_RULES = [
|
|
67
68
|
[/(:?_authToken=)([^\s&]+)/gi, keepPrefix],
|
|
68
|
-
[
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
[
|
|
70
|
+
new RegExp(`(--(?:${SECRET_FLAG_NAMES})=)(\\S+)`, "gi"),
|
|
71
|
+
keepPrefix
|
|
72
|
+
],
|
|
73
|
+
[
|
|
74
|
+
new RegExp(`(--(?:${SECRET_FLAG_NAMES})\\s+)(?!-)(\\S+)`, "gi"),
|
|
75
|
+
keepPrefix
|
|
76
|
+
],
|
|
77
|
+
[
|
|
78
|
+
/(\/\/[^/:@\s]+:)([^/@\s]+)@/g,
|
|
79
|
+
(_match, prefix, value) => `${prefix}${keepEnds(value)}@`
|
|
80
|
+
],
|
|
71
81
|
[/npm_[A-Za-z0-9]{10,}/g, keepEnds],
|
|
72
82
|
[/gh[posru]_[A-Za-z0-9]{20,}/g, keepEnds],
|
|
73
83
|
[/github_pat_\w{20,}/g, keepEnds],
|
|
@@ -124,7 +134,10 @@ async function execPromise(command, {
|
|
|
124
134
|
killSignal,
|
|
125
135
|
shell,
|
|
126
136
|
signal,
|
|
127
|
-
env: env ? {
|
|
137
|
+
env: env ? {
|
|
138
|
+
...process$1.env,
|
|
139
|
+
...env
|
|
140
|
+
} : void 0
|
|
128
141
|
}, (error, stdout, stderr) => {
|
|
129
142
|
if (stdout) {
|
|
130
143
|
internalLogger.debug(`${safeCommand} - stdout output:`, redactSecrets(stdout));
|
|
@@ -184,475 +197,4 @@ function printBanner({
|
|
|
184
197
|
logger.break();
|
|
185
198
|
}
|
|
186
199
|
|
|
187
|
-
|
|
188
|
-
const MANAGED_MARKER = "Managed by maz-ui";
|
|
189
|
-
const AGENTS_MD_BEGIN = "<!-- BEGIN:maz-ui -->";
|
|
190
|
-
const AGENTS_MD_END = "<!-- END:maz-ui -->";
|
|
191
|
-
const MCP_SERVER_NAME = "maz-ui";
|
|
192
|
-
const DEFAULT_MCP_SERVER = { command: "npx", args: ["-y", "@maz-ui/mcp@latest"] };
|
|
193
|
-
const MAZ_UI_AGENTS_TOOL = {
|
|
194
|
-
name: "maz-ui",
|
|
195
|
-
mcpPackage: "@maz-ui/mcp",
|
|
196
|
-
mcpBin: "maz-ui-mcp",
|
|
197
|
-
generatedBy: "`npx @maz-ui/mcp init` (or the `mazUi.agents` Nuxt option)",
|
|
198
|
-
versionNote: (version) => `> maz-ui ${version} is installed: these rules and the docs in \`node_modules/maz-ui/docs\` match this version.`
|
|
199
|
-
};
|
|
200
|
-
function escapeRegExp(value) {
|
|
201
|
-
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
202
|
-
}
|
|
203
|
-
const toolSetups = /* @__PURE__ */ new WeakMap();
|
|
204
|
-
function resolveTool(tool) {
|
|
205
|
-
let setup = toolSetups.get(tool);
|
|
206
|
-
if (!setup) {
|
|
207
|
-
const marker = `Managed by ${tool.name}`;
|
|
208
|
-
setup = {
|
|
209
|
-
tool,
|
|
210
|
-
marker,
|
|
211
|
-
agentsMdBegin: `<!-- BEGIN:${tool.name} -->`,
|
|
212
|
-
agentsMdEnd: `<!-- END:${tool.name} -->`,
|
|
213
|
-
ruleFile: `.claude/rules/${tool.name}.md`,
|
|
214
|
-
managedHeader: new RegExp(`<!-- ${escapeRegExp(marker)}[^\\n]*?-->`),
|
|
215
|
-
managedVersion: new RegExp(`${escapeRegExp(marker)} (\\d[^\\s:]*)`)
|
|
216
|
-
};
|
|
217
|
-
toolSetups.set(tool, setup);
|
|
218
|
-
}
|
|
219
|
-
return setup;
|
|
220
|
-
}
|
|
221
|
-
function readPackageJson(rootDir) {
|
|
222
|
-
try {
|
|
223
|
-
return JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"));
|
|
224
|
-
} catch {
|
|
225
|
-
return void 0;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
function installsMcpPackage(rootDir, tool = MAZ_UI_AGENTS_TOOL) {
|
|
229
|
-
const pkg = readPackageJson(rootDir);
|
|
230
|
-
return ["dependencies", "devDependencies", "optionalDependencies"].some((field) => pkg?.[field]?.[tool.mcpPackage] !== void 0);
|
|
231
|
-
}
|
|
232
|
-
function detectPackageManager(rootDir) {
|
|
233
|
-
const declared = String(readPackageJson(rootDir)?.packageManager ?? "").split("@")[0];
|
|
234
|
-
if (["pnpm", "yarn", "bun", "npm"].includes(declared))
|
|
235
|
-
return declared;
|
|
236
|
-
const lockfiles = [["pnpm-lock.yaml", "pnpm"], ["yarn.lock", "yarn"], ["bun.lock", "bun"], ["bun.lockb", "bun"]];
|
|
237
|
-
return lockfiles.find(([file]) => existsSync(join(rootDir, file)))?.[1] ?? "npm";
|
|
238
|
-
}
|
|
239
|
-
function localMcpCommands(tool) {
|
|
240
|
-
const bin = [tool.mcpBin, ...tool.mcpArgs ?? []];
|
|
241
|
-
return {
|
|
242
|
-
pnpm: { command: "pnpm", args: ["exec", ...bin] },
|
|
243
|
-
yarn: { command: "yarn", args: ["run", ...bin] },
|
|
244
|
-
bun: { command: "bun", args: ["x", "--no-install", ...bin] },
|
|
245
|
-
npm: { command: "npx", args: ["--no-install", ...bin] }
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
function mcpServerCommand(rootDir, version = "latest", tool = MAZ_UI_AGENTS_TOOL) {
|
|
249
|
-
return installsMcpPackage(rootDir, tool) ? localMcpCommands(tool)[detectPackageManager(rootDir)] : { command: "npx", args: ["-y", `${tool.mcpPackage}@${version}`, ...tool.mcpArgs ?? []] };
|
|
250
|
-
}
|
|
251
|
-
function pinnedMcpVersion(server, tool) {
|
|
252
|
-
const pinned = new RegExp(`^${escapeRegExp(tool.mcpPackage)}@(\\d\\S*)$`);
|
|
253
|
-
return server.args.map((arg) => pinned.exec(arg)?.[1]).find(Boolean);
|
|
254
|
-
}
|
|
255
|
-
function isGeneratedMcpCommand(server, tool) {
|
|
256
|
-
const command = [server.command, ...Array.isArray(server.args) ? server.args : []].join(" ");
|
|
257
|
-
const args = (tool.mcpArgs ?? []).map((arg) => ` ${escapeRegExp(arg)}`).join("");
|
|
258
|
-
return new RegExp(`^npx -y ${escapeRegExp(tool.mcpPackage)}(?:@\\S+)?${args}$`).test(command) || Object.values(localMcpCommands(tool)).some((local) => command === [local.command, ...local.args].join(" "));
|
|
259
|
-
}
|
|
260
|
-
const CLAUDE_MEMORY_FILES = ["CLAUDE.md", ".claude/CLAUDE.md", "CLAUDE.local.md"];
|
|
261
|
-
function withVersion(content, version, tool) {
|
|
262
|
-
const note = tool.versionNote?.(version) ?? `> ${tool.name} ${version} is installed: these rules match this version.`;
|
|
263
|
-
return content.replace(/^(#{1,2} .+)\n/, (_, title) => `${title}
|
|
264
|
-
|
|
265
|
-
${note}
|
|
266
|
-
`);
|
|
267
|
-
}
|
|
268
|
-
function checksum(body) {
|
|
269
|
-
return createHash("sha256").update(body.replaceAll(/\s+/g, "")).digest("hex").slice(0, 12);
|
|
270
|
-
}
|
|
271
|
-
function managedContent(version, body, setup) {
|
|
272
|
-
return `<!-- ${setup.marker} ${version} (sha256:${checksum(body)}): generated by ${setup.tool.generatedBy}. Do not edit: edited rules are no longer updated. Write your own rules elsewhere. -->
|
|
273
|
-
|
|
274
|
-
${body}`;
|
|
275
|
-
}
|
|
276
|
-
function isEditedManagedContent(content, tool = MAZ_UI_AGENTS_TOOL) {
|
|
277
|
-
const header = content === void 0 ? null : resolveTool(tool).managedHeader.exec(content);
|
|
278
|
-
const recorded = header ? /\(sha256:([\da-f]+)\)/.exec(header[0])?.[1] : void 0;
|
|
279
|
-
return header !== null && recorded !== void 0 && checksum(content.slice(header.index + header[0].length)) !== recorded;
|
|
280
|
-
}
|
|
281
|
-
function detectAgentTargets(rootDir) {
|
|
282
|
-
const has = (path) => existsSync(join(rootDir, path));
|
|
283
|
-
const targets = /* @__PURE__ */ new Set();
|
|
284
|
-
if (has(".claude") || CLAUDE_MEMORY_FILES.some(has) || has(".mcp.json"))
|
|
285
|
-
targets.add("claude");
|
|
286
|
-
if (has(".cursor") || has(".cursorrules"))
|
|
287
|
-
targets.add("cursor");
|
|
288
|
-
if (has(".vscode/mcp.json") || has(".github/copilot-instructions.md") || has(".github/instructions"))
|
|
289
|
-
targets.add("vscode");
|
|
290
|
-
if (has("AGENTS.md") || targets.has("cursor") || targets.has("vscode") || has(".codex") || has(".windsurf") || has(".devin") || has(".windsurfrules") || has("GEMINI.md"))
|
|
291
|
-
targets.add("agents-md");
|
|
292
|
-
return AGENT_TARGETS.filter((target) => targets.has(target));
|
|
293
|
-
}
|
|
294
|
-
function findInstalledPackage(fromDir, name) {
|
|
295
|
-
let directory = fromDir;
|
|
296
|
-
for (; ; ) {
|
|
297
|
-
const candidate = join(directory, "node_modules", name);
|
|
298
|
-
if (existsSync(join(candidate, "package.json")))
|
|
299
|
-
return candidate;
|
|
300
|
-
const parent = dirname(directory);
|
|
301
|
-
if (parent === directory)
|
|
302
|
-
return void 0;
|
|
303
|
-
directory = parent;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
function readPackageVersion(packageDir) {
|
|
307
|
-
const file = join(packageDir, "package.json");
|
|
308
|
-
return existsSync(file) ? JSON.parse(readFileSync(file, "utf8")).version : void 0;
|
|
309
|
-
}
|
|
310
|
-
const DEFAULT_WORKSPACES = ["apps/*", "packages/*"];
|
|
311
|
-
const MAX_GLOBSTAR_DEPTH = 3;
|
|
312
|
-
function readWorkspacePatterns(rootDir) {
|
|
313
|
-
const pnpmWorkspace = join(rootDir, "pnpm-workspace.yaml");
|
|
314
|
-
const workspaces = readPackageJson(rootDir)?.workspaces;
|
|
315
|
-
const declared = existsSync(pnpmWorkspace) ? readPnpmWorkspacePackages(readFileSync(pnpmWorkspace, "utf8")) : (Array.isArray(workspaces) ? workspaces : workspaces?.packages) ?? [];
|
|
316
|
-
const patterns = declared.filter((pattern) => !pattern.startsWith("!")).map((pattern) => pattern.replace(/^\.\//, "").replace(/\/$/, ""));
|
|
317
|
-
return patterns.length > 0 ? patterns : DEFAULT_WORKSPACES;
|
|
318
|
-
}
|
|
319
|
-
function readPnpmWorkspacePackages(content) {
|
|
320
|
-
const patterns = [];
|
|
321
|
-
let inPackages = false;
|
|
322
|
-
for (const line of content.split(/\r?\n/)) {
|
|
323
|
-
const trimmed = line.trim();
|
|
324
|
-
if (!trimmed || trimmed.startsWith("#"))
|
|
325
|
-
continue;
|
|
326
|
-
if (line === line.trimStart())
|
|
327
|
-
inPackages = trimmed === "packages:";
|
|
328
|
-
else if (inPackages && trimmed.startsWith("-"))
|
|
329
|
-
patterns.push(trimmed.slice(1).split("#")[0].trim().replaceAll(/^["']|["']$/g, ""));
|
|
330
|
-
}
|
|
331
|
-
return patterns;
|
|
332
|
-
}
|
|
333
|
-
function globToRegExp(pattern) {
|
|
334
|
-
const source = pattern.split("/").map((segment) => segment === "**" ? ".*" : segment.replaceAll(/[.+^${}()|[\]\\]/g, "\\$&").replaceAll("*", "[^/]*").replaceAll("?", "[^/]")).join("/");
|
|
335
|
-
return new RegExp(`^${source.replaceAll("/.*", "(?:/.*)?")}$`);
|
|
336
|
-
}
|
|
337
|
-
function findWorkspaceDirs(rootDir) {
|
|
338
|
-
const folders = /* @__PURE__ */ new Set();
|
|
339
|
-
for (const pattern of readWorkspacePatterns(rootDir)) {
|
|
340
|
-
const segments = pattern.split("/");
|
|
341
|
-
const firstGlob = segments.findIndex((segment) => /[*?[{]/.test(segment));
|
|
342
|
-
const base = (firstGlob === -1 ? segments : segments.slice(0, firstGlob)).join("/");
|
|
343
|
-
const depth = firstGlob === -1 ? 0 : segments.includes("**") ? MAX_GLOBSTAR_DEPTH : segments.length - firstGlob;
|
|
344
|
-
const matcher = globToRegExp(pattern);
|
|
345
|
-
const visit = (folder, remaining) => {
|
|
346
|
-
if (!existsSync(join(rootDir, folder)))
|
|
347
|
-
return;
|
|
348
|
-
if (folder && folder !== "." && matcher.test(folder))
|
|
349
|
-
folders.add(join(rootDir, folder));
|
|
350
|
-
if (remaining === 0)
|
|
351
|
-
return;
|
|
352
|
-
for (const entry of readdirSync(join(rootDir, folder), { withFileTypes: true })) {
|
|
353
|
-
if (entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith("."))
|
|
354
|
-
visit(folder ? `${folder}/${entry.name}` : entry.name, remaining - 1);
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
visit(base, depth);
|
|
358
|
-
}
|
|
359
|
-
return [...folders];
|
|
360
|
-
}
|
|
361
|
-
function findProjectPackage(rootDir, name) {
|
|
362
|
-
return [rootDir, ...findWorkspaceDirs(rootDir)].map((base) => join(base, "node_modules", name)).find((candidate) => existsSync(join(candidate, "package.json"))) ?? findInstalledPackage(rootDir, name);
|
|
363
|
-
}
|
|
364
|
-
function readAgentDocs(rootDir, docsDir) {
|
|
365
|
-
let directory = docsDir;
|
|
366
|
-
if (!directory) {
|
|
367
|
-
const packageDir = findProjectPackage(rootDir, "maz-ui");
|
|
368
|
-
if (!packageDir)
|
|
369
|
-
throw new Error(`maz-ui is not installed in ${rootDir}: install it first (\`npm install maz-ui\`).`);
|
|
370
|
-
directory = join(packageDir, "docs");
|
|
371
|
-
}
|
|
372
|
-
const manifestFile = join(directory, "manifest.json");
|
|
373
|
-
const claudeRuleFile = join(directory, "agents/claude-rule.md");
|
|
374
|
-
const agentsMdFile = join(directory, "agents/agents-md.md");
|
|
375
|
-
if (!existsSync(manifestFile) || !existsSync(claudeRuleFile) || !existsSync(agentsMdFile)) {
|
|
376
|
-
throw new Error(`The installed maz-ui does not ship the agent docs (${directory}): upgrade maz-ui to the latest version.`);
|
|
377
|
-
}
|
|
378
|
-
const packageVersion = readPackageVersion(dirname(directory));
|
|
379
|
-
return {
|
|
380
|
-
directory,
|
|
381
|
-
version: packageVersion ?? JSON.parse(readFileSync(manifestFile, "utf8")).version,
|
|
382
|
-
claudeRule: readFileSync(claudeRuleFile, "utf8").trim(),
|
|
383
|
-
agentsMdSection: readFileSync(agentsMdFile, "utf8").trim()
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
function writeFileAtomic(path, content) {
|
|
387
|
-
const temporary = join(dirname(path), `.${basename(path)}.${process.pid}.${Date.now()}.tmp`);
|
|
388
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
389
|
-
try {
|
|
390
|
-
writeFileSync(temporary, content);
|
|
391
|
-
renameSync(temporary, path);
|
|
392
|
-
} catch (error) {
|
|
393
|
-
rmSync(temporary, { force: true });
|
|
394
|
-
throw error;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
function parseVersion(version) {
|
|
398
|
-
const [core, ...prerelease] = version.replace(/^v/, "").split("+")[0].split("-");
|
|
399
|
-
return {
|
|
400
|
-
core: core.split(".").map((part) => Number.parseInt(part, 10) || 0),
|
|
401
|
-
prerelease: prerelease.join("-").split(".").filter(Boolean)
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
function comparePrereleaseIdentifiers(a, b) {
|
|
405
|
-
const isNumeric = (value) => /^\d+$/.test(value);
|
|
406
|
-
if (isNumeric(a) !== isNumeric(b))
|
|
407
|
-
return isNumeric(a) ? -1 : 1;
|
|
408
|
-
return isNumeric(a) ? Number(a) - Number(b) : a.localeCompare(b);
|
|
409
|
-
}
|
|
410
|
-
function compareVersions(a, b) {
|
|
411
|
-
const left = parseVersion(a);
|
|
412
|
-
const right = parseVersion(b);
|
|
413
|
-
for (let index = 0; index < 3; index++) {
|
|
414
|
-
const difference = (left.core[index] ?? 0) - (right.core[index] ?? 0);
|
|
415
|
-
if (difference !== 0)
|
|
416
|
-
return difference;
|
|
417
|
-
}
|
|
418
|
-
if (left.prerelease.length === 0 || right.prerelease.length === 0)
|
|
419
|
-
return right.prerelease.length - left.prerelease.length;
|
|
420
|
-
for (let index = 0; index < Math.min(left.prerelease.length, right.prerelease.length); index++) {
|
|
421
|
-
const difference = comparePrereleaseIdentifiers(left.prerelease[index], right.prerelease[index]);
|
|
422
|
-
if (difference !== 0)
|
|
423
|
-
return difference;
|
|
424
|
-
}
|
|
425
|
-
return left.prerelease.length - right.prerelease.length;
|
|
426
|
-
}
|
|
427
|
-
function readManagedVersion(content, tool = MAZ_UI_AGENTS_TOOL) {
|
|
428
|
-
return content ? resolveTool(tool).managedVersion.exec(content)?.[1] : void 0;
|
|
429
|
-
}
|
|
430
|
-
function newerManagedVersion(content, version, tool) {
|
|
431
|
-
const written = readManagedVersion(content, tool);
|
|
432
|
-
return written && version && compareVersions(written, version) > 0 ? written : void 0;
|
|
433
|
-
}
|
|
434
|
-
function newerVersionReason(written, version, tool) {
|
|
435
|
-
return `written by ${tool.name} ${written}, newer than the installed ${version}: left untouched`;
|
|
436
|
-
}
|
|
437
|
-
class ChangeSet {
|
|
438
|
-
constructor(rootDir, dryRun) {
|
|
439
|
-
this.rootDir = rootDir;
|
|
440
|
-
this.dryRun = dryRun;
|
|
441
|
-
}
|
|
442
|
-
changes = [];
|
|
443
|
-
absolute(file) {
|
|
444
|
-
return join(this.rootDir, file);
|
|
445
|
-
}
|
|
446
|
-
read(file) {
|
|
447
|
-
const path = this.absolute(file);
|
|
448
|
-
return existsSync(path) ? readFileSync(path, "utf8") : void 0;
|
|
449
|
-
}
|
|
450
|
-
write(file, content, current, reason) {
|
|
451
|
-
if (current === content) {
|
|
452
|
-
this.changes.push({ file, action: "unchanged" });
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
this.changes.push({ file, action: current === void 0 ? "create" : "update", ...reason ? { reason } : {} });
|
|
456
|
-
if (!this.dryRun)
|
|
457
|
-
writeFileAtomic(this.absolute(file), content);
|
|
458
|
-
}
|
|
459
|
-
delete(file) {
|
|
460
|
-
this.changes.push({ file, action: "remove" });
|
|
461
|
-
if (!this.dryRun)
|
|
462
|
-
rmSync(this.absolute(file), { force: true });
|
|
463
|
-
}
|
|
464
|
-
skip(file, reason) {
|
|
465
|
-
this.changes.push({ file, action: "skip", reason });
|
|
466
|
-
}
|
|
467
|
-
unchanged(file, reason) {
|
|
468
|
-
this.changes.push({ file, action: "unchanged", reason });
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
function isOwned(content, setup) {
|
|
472
|
-
return content === void 0 || content.includes(setup.marker);
|
|
473
|
-
}
|
|
474
|
-
function syncOwnedFile(changes, file, content, version, setup) {
|
|
475
|
-
const { tool } = setup;
|
|
476
|
-
const current = changes.read(file);
|
|
477
|
-
if (!isOwned(current, setup)) {
|
|
478
|
-
changes.skip(file, `file exists and was not generated by ${tool.name}: left untouched`);
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
const newer = content === void 0 ? void 0 : newerManagedVersion(current, version, tool);
|
|
482
|
-
if (newer) {
|
|
483
|
-
changes.skip(file, newerVersionReason(newer, version, tool));
|
|
484
|
-
return;
|
|
485
|
-
}
|
|
486
|
-
if (content !== void 0 && isEditedManagedContent(current, tool)) {
|
|
487
|
-
changes.skip(file, `edited since it was generated: left untouched, delete it to get the rules of ${tool.name} ${version}`);
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
if (content === void 0) {
|
|
491
|
-
if (current !== void 0)
|
|
492
|
-
changes.delete(file);
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
changes.write(file, content, current);
|
|
496
|
-
}
|
|
497
|
-
function syncAgentsMd(changes, section, version, setup) {
|
|
498
|
-
const { tool, agentsMdBegin, agentsMdEnd } = setup;
|
|
499
|
-
const file = "AGENTS.md";
|
|
500
|
-
const current = changes.read(file);
|
|
501
|
-
const begin = current?.indexOf(agentsMdBegin) ?? -1;
|
|
502
|
-
const end = current?.indexOf(agentsMdEnd) ?? -1;
|
|
503
|
-
const hasBlock = begin !== -1 && end > begin;
|
|
504
|
-
if (section === void 0) {
|
|
505
|
-
if (!current || !hasBlock)
|
|
506
|
-
return;
|
|
507
|
-
const remaining = `${current.slice(0, begin)}${current.slice(end + agentsMdEnd.length)}`.replace(/\n{3,}/g, "\n\n").trim();
|
|
508
|
-
if (remaining)
|
|
509
|
-
changes.write(file, `${remaining}
|
|
510
|
-
`, current);
|
|
511
|
-
else
|
|
512
|
-
changes.delete(file);
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
const block = hasBlock ? current?.slice(begin + agentsMdBegin.length, end) : void 0;
|
|
516
|
-
const newer = newerManagedVersion(block, version, tool);
|
|
517
|
-
if (newer) {
|
|
518
|
-
changes.skip(file, newerVersionReason(newer, version, tool));
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
if (isEditedManagedContent(block, tool)) {
|
|
522
|
-
changes.skip(file, `the ${tool.name} section was edited since it was generated: left untouched, delete the section to get the rules of ${tool.name} ${version}`);
|
|
523
|
-
return;
|
|
524
|
-
}
|
|
525
|
-
const wrapped = `${agentsMdBegin}
|
|
526
|
-
|
|
527
|
-
${section}
|
|
528
|
-
|
|
529
|
-
${agentsMdEnd}`;
|
|
530
|
-
if (!current) {
|
|
531
|
-
changes.write(file, `${wrapped}
|
|
532
|
-
`, current);
|
|
533
|
-
} else if (hasBlock) {
|
|
534
|
-
changes.write(file, `${current.slice(0, begin)}${wrapped}${current.slice(end + agentsMdEnd.length)}`, current);
|
|
535
|
-
} else {
|
|
536
|
-
changes.write(file, `${current.trimEnd()}
|
|
537
|
-
|
|
538
|
-
${wrapped}
|
|
539
|
-
`, current);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
const MCP_FILES = {
|
|
543
|
-
claude: { file: ".mcp.json", rootKey: "mcpServers", withType: true },
|
|
544
|
-
cursor: { file: ".cursor/mcp.json", rootKey: "mcpServers", withType: false },
|
|
545
|
-
vscode: { file: ".vscode/mcp.json", rootKey: "servers", withType: true }
|
|
546
|
-
};
|
|
547
|
-
function referencesToolMcp(server, tool) {
|
|
548
|
-
const serialized = JSON.stringify(server);
|
|
549
|
-
const args = isJsonObject(server) && Array.isArray(server.args) ? server.args : [];
|
|
550
|
-
return (serialized.includes(tool.mcpPackage) || serialized.includes(tool.mcpBin)) && (tool.mcpArgs ?? []).every((arg) => args.includes(arg));
|
|
551
|
-
}
|
|
552
|
-
function detectFormatting(content) {
|
|
553
|
-
const indent = /^( +|\t)"/m.exec(content)?.[1] ?? " ";
|
|
554
|
-
return { insertSpaces: !indent.includes(" "), tabSize: indent.includes(" ") ? 1 : indent.length, eol: content.includes("\r\n") ? "\r\n" : "\n" };
|
|
555
|
-
}
|
|
556
|
-
function isJsonObject(value) {
|
|
557
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
558
|
-
}
|
|
559
|
-
function updateMcpCommand(changes, config, [key, entry], server, tool) {
|
|
560
|
-
const current = entry;
|
|
561
|
-
const label = [server.command, ...server.args].join(" ");
|
|
562
|
-
if (current.command === server.command && JSON.stringify(current.args) === JSON.stringify(server.args)) {
|
|
563
|
-
changes.unchanged(config.file, `${tool.name} MCP server already registered as "${key}"`);
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
if (!isGeneratedMcpCommand(current, tool)) {
|
|
567
|
-
changes.unchanged(config.file, `"${key}" runs a custom command: left untouched`);
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
const pinned = pinnedMcpVersion(current, tool);
|
|
571
|
-
const wanted = pinnedMcpVersion(server, tool);
|
|
572
|
-
const isLocal = !server.args.includes("-y");
|
|
573
|
-
if (pinned && !isLocal && (!wanted || compareVersions(pinned, wanted) >= 0)) {
|
|
574
|
-
changes.unchanged(config.file, `"${key}" runs ${tool.mcpPackage} ${pinned}`);
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
const file = changes.read(config.file);
|
|
578
|
-
const formatting = detectFormatting(file);
|
|
579
|
-
let content = applyEdits(file, modify(file, [config.rootKey, key, "command"], server.command, { formattingOptions: formatting }));
|
|
580
|
-
content = applyEdits(content, modify(content, [config.rootKey, key, "args"], server.args, { formattingOptions: formatting }));
|
|
581
|
-
changes.write(config.file, content, file, `"${key}" now runs ${label}`);
|
|
582
|
-
}
|
|
583
|
-
function syncMcpConfig(changes, config, server, remove, tool) {
|
|
584
|
-
const current = changes.read(config.file);
|
|
585
|
-
const errors = [];
|
|
586
|
-
const parsed = current === void 0 ? {} : parse(current, errors, { allowTrailingComma: true });
|
|
587
|
-
if (errors.length > 0 || !isJsonObject(parsed) || parsed[config.rootKey] !== void 0 && !isJsonObject(parsed[config.rootKey])) {
|
|
588
|
-
changes.skip(config.file, "invalid JSON: left untouched");
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
const servers = parsed[config.rootKey] ?? {};
|
|
592
|
-
const existing = Object.entries(servers).find(([, value2]) => referencesToolMcp(value2, tool));
|
|
593
|
-
const base = current ?? "{}\n";
|
|
594
|
-
const formatting = detectFormatting(base);
|
|
595
|
-
if (remove) {
|
|
596
|
-
if (existing?.[0] === tool.name) {
|
|
597
|
-
const content2 = applyEdits(base, modify(base, [config.rootKey, tool.name], void 0, { formattingOptions: formatting }));
|
|
598
|
-
const remaining = parse(content2);
|
|
599
|
-
const isEmpty = Object.keys(remaining).length === 1 && Object.keys(remaining[config.rootKey]).length === 0;
|
|
600
|
-
if (isEmpty)
|
|
601
|
-
changes.delete(config.file);
|
|
602
|
-
else
|
|
603
|
-
changes.write(config.file, content2, current);
|
|
604
|
-
}
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
if (existing) {
|
|
608
|
-
updateMcpCommand(changes, config, existing, server, tool);
|
|
609
|
-
return;
|
|
610
|
-
}
|
|
611
|
-
if (servers[tool.name] !== void 0) {
|
|
612
|
-
changes.skip(config.file, `a "${tool.name}" server already exists with another command: left untouched`);
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
const value = config.withType ? { type: "stdio", ...server } : { ...server };
|
|
616
|
-
const content = applyEdits(base, modify(base, [config.rootKey, tool.name], value, { formattingOptions: formatting }));
|
|
617
|
-
changes.write(config.file, content.endsWith("\n") ? content : `${content}
|
|
618
|
-
`, current);
|
|
619
|
-
}
|
|
620
|
-
function syncRules(changes, rootDir, targets, docs, setup) {
|
|
621
|
-
const version = docs?.version ?? "";
|
|
622
|
-
const hasClaudeMemory = CLAUDE_MEMORY_FILES.some((file) => existsSync(join(rootDir, file)));
|
|
623
|
-
const claudeReadsAgentsMd = targets.includes("agents-md") && !hasClaudeMemory;
|
|
624
|
-
if (targets.includes("claude")) {
|
|
625
|
-
const rule = docs && !claudeReadsAgentsMd ? `${managedContent(version, withVersion(docs.claudeRule, version, setup.tool), setup)}
|
|
626
|
-
` : void 0;
|
|
627
|
-
syncOwnedFile(changes, setup.ruleFile, rule, version, setup);
|
|
628
|
-
}
|
|
629
|
-
if (targets.includes("agents-md"))
|
|
630
|
-
syncAgentsMd(changes, docs ? managedContent(version, withVersion(docs.agentsMdSection, version, setup.tool), setup) : void 0, version, setup);
|
|
631
|
-
}
|
|
632
|
-
function resolveAgentDocs(options, tool) {
|
|
633
|
-
if (options.agentDocs)
|
|
634
|
-
return options.agentDocs;
|
|
635
|
-
if (tool !== MAZ_UI_AGENTS_TOOL)
|
|
636
|
-
throw new Error(`setupAgents needs the rules of ${tool.name}: pass them with the agentDocs option.`);
|
|
637
|
-
return readAgentDocs(options.rootDir, options.docsDir);
|
|
638
|
-
}
|
|
639
|
-
function setupAgents(options) {
|
|
640
|
-
const { rootDir, rules = true, mcp = true, dryRun = false, remove = false, tool = MAZ_UI_AGENTS_TOOL } = options;
|
|
641
|
-
const setup = resolveTool(tool);
|
|
642
|
-
const targets = options.targets ?? detectAgentTargets(rootDir);
|
|
643
|
-
const docs = remove || !rules ? void 0 : resolveAgentDocs(options, tool);
|
|
644
|
-
const version = docs?.version ?? "";
|
|
645
|
-
const changes = new ChangeSet(rootDir, dryRun);
|
|
646
|
-
const server = options.mcpServer ?? mcpServerCommand(rootDir, options.mcpVersion, tool);
|
|
647
|
-
if (rules || remove)
|
|
648
|
-
syncRules(changes, rootDir, targets, docs, setup);
|
|
649
|
-
if (mcp || remove) {
|
|
650
|
-
for (const target of ["claude", "cursor", "vscode"]) {
|
|
651
|
-
if (targets.includes(target))
|
|
652
|
-
syncMcpConfig(changes, MCP_FILES[target], server, remove, tool);
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
return { targets, version, changes: changes.changes, mcpServer: server, localMcpServer: !server.args.includes("-y") };
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
export { AGENTS_MD_BEGIN, AGENTS_MD_END, AGENT_TARGETS, DEFAULT_MCP_SERVER, MANAGED_MARKER, MAZ_UI_AGENTS_TOOL, MCP_SERVER_NAME, compareVersions, createLogger, detectAgentTargets, detectPackageManager, execPromise, findInstalledPackage, findProjectPackage, findWorkspaceDirs, installsMcpPackage, isEditedManagedContent, logger, mcpServerCommand, printBanner, readAgentDocs, readManagedVersion, readPackageVersion, readWorkspacePatterns, redactError, redactSecrets, setupAgents, writeFileAtomic };
|
|
200
|
+
export { createLogger, execPromise, logger, printBanner, redactError, redactSecrets };
|