@maz-ui/node 5.1.0 → 5.2.0-beta.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/index.d.mts +85 -21
- package/dist/index.d.ts +85 -21
- package/dist/index.mjs +281 -63
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ npm install @maz-ui/node
|
|
|
18
18
|
- 🔧 **Highly configurable** - custom loggers with different levels and reporters
|
|
19
19
|
- 🛡️ **Error handling** - comprehensive error management
|
|
20
20
|
- 🎯 **Multiple log types** - info, debug, trace, start, ready, fail, box
|
|
21
|
-
- 🤖 **AI agents setup** - `setupAgents` configures the AI coding agents of a project for maz-ui (rules and MCP server), as `npx @maz-ui/mcp init` does: [documentation](https://maz-ui.com/ecosystem/node/setup-agents)
|
|
21
|
+
- 🤖 **AI agents setup** - `setupAgents` configures the AI coding agents of a project for maz-ui (rules and MCP server), as `npx @maz-ui/mcp init` does, or for another tool that ships its own MCP server and rules (`tool` option): [documentation](https://maz-ui.com/ecosystem/node/setup-agents)
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
24
24
|
|
package/dist/index.d.mts
CHANGED
|
@@ -171,7 +171,7 @@ declare function redactError<T>(error: T): T;
|
|
|
171
171
|
/**
|
|
172
172
|
* AI coding agents supported by `setupAgents`.
|
|
173
173
|
*
|
|
174
|
-
* - `claude`: Claude Code rule (`.claude/rules
|
|
174
|
+
* - `claude`: Claude Code rule (`.claude/rules/<tool>.md`) and MCP server (`.mcp.json`)
|
|
175
175
|
* - `agents-md`: section in `AGENTS.md` (Codex, Cursor, Copilot, Windsurf, Zed, Gemini...)
|
|
176
176
|
* - `cursor`: MCP server in `.cursor/mcp.json` (rules come from `AGENTS.md`)
|
|
177
177
|
* - `vscode`: MCP server in `.vscode/mcp.json` for GitHub Copilot (rules come from `AGENTS.md`)
|
|
@@ -183,9 +183,9 @@ interface SetupAgentsOptions {
|
|
|
183
183
|
rootDir: string;
|
|
184
184
|
/** Agents to configure. Default: the agents detected in the project */
|
|
185
185
|
targets?: AgentTarget[];
|
|
186
|
-
/** Write the
|
|
186
|
+
/** Write the rules of the tool (Claude Code rule, `AGENTS.md` section). Default `true` */
|
|
187
187
|
rules?: boolean;
|
|
188
|
-
/** Register the
|
|
188
|
+
/** Register the MCP server of the tool. Default `true` */
|
|
189
189
|
mcp?: boolean;
|
|
190
190
|
/** Compute the changes without writing anything */
|
|
191
191
|
dryRun?: boolean;
|
|
@@ -193,11 +193,18 @@ interface SetupAgentsOptions {
|
|
|
193
193
|
remove?: boolean;
|
|
194
194
|
/** Folder of the maz-ui agent docs. Default: `docs/` of the maz-ui package installed in `rootDir` */
|
|
195
195
|
docsDir?: string;
|
|
196
|
-
/** Command used to start the MCP server */
|
|
197
|
-
mcpServer?:
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
196
|
+
/** Command used to start the MCP server. Default: `mcpServerCommand(rootDir, mcpVersion, tool)` */
|
|
197
|
+
mcpServer?: McpServerCommand;
|
|
198
|
+
/** Version of the MCP package pinned in the `npx -y` command, when the project does not install it. Default `latest` */
|
|
199
|
+
mcpVersion?: string;
|
|
200
|
+
/** Tool whose agents are configured. Default: maz-ui (`MAZ_UI_AGENTS_TOOL`) */
|
|
201
|
+
tool?: AgentsTool;
|
|
202
|
+
/** Rules of the tool, required with another `tool` than maz-ui. Default: the maz-ui agent docs of `docsDir` */
|
|
203
|
+
agentDocs?: AgentDocs;
|
|
204
|
+
}
|
|
205
|
+
interface McpServerCommand {
|
|
206
|
+
command: string;
|
|
207
|
+
args: string[];
|
|
201
208
|
}
|
|
202
209
|
type SetupAgentsAction = 'create' | 'update' | 'remove' | 'unchanged' | 'skip';
|
|
203
210
|
interface SetupAgentsChange {
|
|
@@ -210,15 +217,54 @@ interface SetupAgentsResult {
|
|
|
210
217
|
targets: AgentTarget[];
|
|
211
218
|
version: string;
|
|
212
219
|
changes: SetupAgentsChange[];
|
|
220
|
+
/** Command registered in the MCP config files */
|
|
221
|
+
mcpServer: McpServerCommand;
|
|
222
|
+
/** `false` when the server runs through `npx -y` because the project does not install the MCP package */
|
|
223
|
+
localMcpServer: boolean;
|
|
213
224
|
}
|
|
214
225
|
declare const MANAGED_MARKER = "Managed by maz-ui";
|
|
215
226
|
declare const AGENTS_MD_BEGIN = "<!-- BEGIN:maz-ui -->";
|
|
216
227
|
declare const AGENTS_MD_END = "<!-- END:maz-ui -->";
|
|
217
228
|
declare const MCP_SERVER_NAME = "maz-ui";
|
|
218
|
-
declare const DEFAULT_MCP_SERVER:
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
229
|
+
declare const DEFAULT_MCP_SERVER: McpServerCommand;
|
|
230
|
+
/**
|
|
231
|
+
* A tool whose AI agents are configured by `setupAgents`: maz-ui by default,
|
|
232
|
+
* or another package that ships its own MCP server and rules.
|
|
233
|
+
*/
|
|
234
|
+
interface AgentsTool {
|
|
235
|
+
/** Name of the tool: key of its MCP server, `.claude/rules/<name>.md` and markers of the generated content */
|
|
236
|
+
name: string;
|
|
237
|
+
/** Package that ships the MCP server */
|
|
238
|
+
mcpPackage: string;
|
|
239
|
+
/** Bin of `mcpPackage` that starts the MCP server */
|
|
240
|
+
mcpBin: string;
|
|
241
|
+
/** Arguments of `mcpBin` that start the MCP server (e.g. `['mcp']`). Default `[]` */
|
|
242
|
+
mcpArgs?: string[];
|
|
243
|
+
/** What generates the rules, written in their header (markdown, e.g. `` `npx relizy mcp init` ``) */
|
|
244
|
+
generatedBy: string;
|
|
245
|
+
/** Line written under the title of the rules. Default: `> <name> <version> is installed: these rules match this version.` */
|
|
246
|
+
versionNote?: (version: string) => string;
|
|
247
|
+
}
|
|
248
|
+
declare const MAZ_UI_AGENTS_TOOL: AgentsTool;
|
|
249
|
+
type PackageManager = 'pnpm' | 'yarn' | 'bun' | 'npm';
|
|
250
|
+
/** `true` when the `package.json` of the project declares the MCP package of the tool (`@maz-ui/mcp` by default) */
|
|
251
|
+
declare function installsMcpPackage(rootDir: string, tool?: AgentsTool): boolean;
|
|
252
|
+
/** Package manager of a project: the `packageManager` field, else its lockfile */
|
|
253
|
+
declare function detectPackageManager(rootDir: string): PackageManager;
|
|
254
|
+
/**
|
|
255
|
+
* Command of the MCP server of a tool (maz-ui by default) for a project. When
|
|
256
|
+
* the project installs its package, the package manager starts the installed
|
|
257
|
+
* version in about a second, at the version of the lockfile. Otherwise
|
|
258
|
+
* `npx -y` downloads it, pinned to `version`: a dist-tag (`latest`) makes npx
|
|
259
|
+
* query the registry at every start, which can exceed the start timeout of the
|
|
260
|
+
* agents behind a slow registry.
|
|
261
|
+
*/
|
|
262
|
+
declare function mcpServerCommand(rootDir: string, version?: string, tool?: AgentsTool): McpServerCommand;
|
|
263
|
+
/**
|
|
264
|
+
* `true` when generated rules were edited by hand since they were written:
|
|
265
|
+
* they are kept, a newer version of the rules would overwrite the edits.
|
|
266
|
+
*/
|
|
267
|
+
declare function isEditedManagedContent(content: string | undefined, tool?: AgentsTool): boolean;
|
|
222
268
|
/** Detects the AI agents configured in a project */
|
|
223
269
|
declare function detectAgentTargets(rootDir: string): AgentTarget[];
|
|
224
270
|
interface AgentDocs {
|
|
@@ -233,23 +279,41 @@ interface AgentDocs {
|
|
|
233
279
|
* package installed for the project is found.
|
|
234
280
|
*/
|
|
235
281
|
declare function findInstalledPackage(fromDir: string, name: string): string | undefined;
|
|
236
|
-
/** Reads the agent files shipped in `maz-ui/docs/agents` */
|
|
237
282
|
/** Version of an installed package, read from its `package.json` */
|
|
238
283
|
declare function readPackageVersion(packageDir: string): string | undefined;
|
|
284
|
+
/**
|
|
285
|
+
* Workspace patterns of a monorepo: the `packages` of `pnpm-workspace.yaml`,
|
|
286
|
+
* else the `workspaces` of `package.json` (npm, yarn, bun), else `apps/*` and
|
|
287
|
+
* `packages/*`. Negated patterns are ignored.
|
|
288
|
+
*/
|
|
289
|
+
declare function readWorkspacePatterns(rootDir: string): string[];
|
|
290
|
+
/** Folders of the workspaces of a monorepo, in the order of the patterns. Only the fixed part of each pattern is read (`apps/*` reads `apps`) */
|
|
291
|
+
declare function findWorkspaceDirs(rootDir: string): string[];
|
|
239
292
|
/**
|
|
240
293
|
* Finds a package installed in a project: in the `node_modules` of the
|
|
241
|
-
* project root and of its
|
|
242
|
-
*
|
|
294
|
+
* project root and of its workspaces (monorepos without hoisting), then in
|
|
295
|
+
* the parent folders.
|
|
243
296
|
*/
|
|
244
297
|
declare function findProjectPackage(rootDir: string, name: string): string | undefined;
|
|
298
|
+
/** Reads the agent files shipped in `maz-ui/docs/agents` */
|
|
245
299
|
declare function readAgentDocs(rootDir: string, docsDir?: string): AgentDocs;
|
|
246
300
|
/**
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
|
|
301
|
+
* Writes a temporary file then renames it: a concurrent reader (several Nuxt
|
|
302
|
+
* apps of a monorepo starting together) sees the old or the new file, never a
|
|
303
|
+
* truncated one.
|
|
304
|
+
*/
|
|
305
|
+
declare function writeFileAtomic(path: string, content: string): void;
|
|
306
|
+
/** Compares two semver versions: negative when `a < b`, positive when `a > b`, `0` when equal */
|
|
307
|
+
declare function compareVersions(a: string, b: string): number;
|
|
308
|
+
/** Version of the tool (maz-ui by default) that generated a managed content, read from its header */
|
|
309
|
+
declare function readManagedVersion(content: string | undefined, tool?: AgentsTool): string | undefined;
|
|
310
|
+
/**
|
|
311
|
+
* Configures the AI coding agents of a project to use a tool, maz-ui by
|
|
312
|
+
* default: rules (version matched with the installed tool) and its MCP server.
|
|
313
|
+
* Idempotent and conservative: it only writes files it owns, a delimited
|
|
314
|
+
* section of `AGENTS.md` and its own entry of the MCP config files.
|
|
251
315
|
*/
|
|
252
316
|
declare function setupAgents(options: SetupAgentsOptions): SetupAgentsResult;
|
|
253
317
|
|
|
254
|
-
export { AGENTS_MD_BEGIN, AGENTS_MD_END, AGENT_TARGETS, DEFAULT_MCP_SERVER, MANAGED_MARKER, MCP_SERVER_NAME, createLogger, detectAgentTargets, execPromise, findInstalledPackage, findProjectPackage, logger, printBanner, readAgentDocs, readPackageVersion, redactError, redactSecrets, setupAgents };
|
|
255
|
-
export type { AgentDocs, AgentTarget, ExecPromiseOptions, LogLevel, Logger, LoggerOptions, SetupAgentsAction, SetupAgentsChange, SetupAgentsOptions, SetupAgentsResult };
|
|
318
|
+
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 };
|
|
319
|
+
export type { AgentDocs, AgentTarget, AgentsTool, ExecPromiseOptions, LogLevel, Logger, LoggerOptions, McpServerCommand, PackageManager, SetupAgentsAction, SetupAgentsChange, SetupAgentsOptions, SetupAgentsResult };
|
package/dist/index.d.ts
CHANGED
|
@@ -171,7 +171,7 @@ declare function redactError<T>(error: T): T;
|
|
|
171
171
|
/**
|
|
172
172
|
* AI coding agents supported by `setupAgents`.
|
|
173
173
|
*
|
|
174
|
-
* - `claude`: Claude Code rule (`.claude/rules
|
|
174
|
+
* - `claude`: Claude Code rule (`.claude/rules/<tool>.md`) and MCP server (`.mcp.json`)
|
|
175
175
|
* - `agents-md`: section in `AGENTS.md` (Codex, Cursor, Copilot, Windsurf, Zed, Gemini...)
|
|
176
176
|
* - `cursor`: MCP server in `.cursor/mcp.json` (rules come from `AGENTS.md`)
|
|
177
177
|
* - `vscode`: MCP server in `.vscode/mcp.json` for GitHub Copilot (rules come from `AGENTS.md`)
|
|
@@ -183,9 +183,9 @@ interface SetupAgentsOptions {
|
|
|
183
183
|
rootDir: string;
|
|
184
184
|
/** Agents to configure. Default: the agents detected in the project */
|
|
185
185
|
targets?: AgentTarget[];
|
|
186
|
-
/** Write the
|
|
186
|
+
/** Write the rules of the tool (Claude Code rule, `AGENTS.md` section). Default `true` */
|
|
187
187
|
rules?: boolean;
|
|
188
|
-
/** Register the
|
|
188
|
+
/** Register the MCP server of the tool. Default `true` */
|
|
189
189
|
mcp?: boolean;
|
|
190
190
|
/** Compute the changes without writing anything */
|
|
191
191
|
dryRun?: boolean;
|
|
@@ -193,11 +193,18 @@ interface SetupAgentsOptions {
|
|
|
193
193
|
remove?: boolean;
|
|
194
194
|
/** Folder of the maz-ui agent docs. Default: `docs/` of the maz-ui package installed in `rootDir` */
|
|
195
195
|
docsDir?: string;
|
|
196
|
-
/** Command used to start the MCP server */
|
|
197
|
-
mcpServer?:
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
196
|
+
/** Command used to start the MCP server. Default: `mcpServerCommand(rootDir, mcpVersion, tool)` */
|
|
197
|
+
mcpServer?: McpServerCommand;
|
|
198
|
+
/** Version of the MCP package pinned in the `npx -y` command, when the project does not install it. Default `latest` */
|
|
199
|
+
mcpVersion?: string;
|
|
200
|
+
/** Tool whose agents are configured. Default: maz-ui (`MAZ_UI_AGENTS_TOOL`) */
|
|
201
|
+
tool?: AgentsTool;
|
|
202
|
+
/** Rules of the tool, required with another `tool` than maz-ui. Default: the maz-ui agent docs of `docsDir` */
|
|
203
|
+
agentDocs?: AgentDocs;
|
|
204
|
+
}
|
|
205
|
+
interface McpServerCommand {
|
|
206
|
+
command: string;
|
|
207
|
+
args: string[];
|
|
201
208
|
}
|
|
202
209
|
type SetupAgentsAction = 'create' | 'update' | 'remove' | 'unchanged' | 'skip';
|
|
203
210
|
interface SetupAgentsChange {
|
|
@@ -210,15 +217,54 @@ interface SetupAgentsResult {
|
|
|
210
217
|
targets: AgentTarget[];
|
|
211
218
|
version: string;
|
|
212
219
|
changes: SetupAgentsChange[];
|
|
220
|
+
/** Command registered in the MCP config files */
|
|
221
|
+
mcpServer: McpServerCommand;
|
|
222
|
+
/** `false` when the server runs through `npx -y` because the project does not install the MCP package */
|
|
223
|
+
localMcpServer: boolean;
|
|
213
224
|
}
|
|
214
225
|
declare const MANAGED_MARKER = "Managed by maz-ui";
|
|
215
226
|
declare const AGENTS_MD_BEGIN = "<!-- BEGIN:maz-ui -->";
|
|
216
227
|
declare const AGENTS_MD_END = "<!-- END:maz-ui -->";
|
|
217
228
|
declare const MCP_SERVER_NAME = "maz-ui";
|
|
218
|
-
declare const DEFAULT_MCP_SERVER:
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
229
|
+
declare const DEFAULT_MCP_SERVER: McpServerCommand;
|
|
230
|
+
/**
|
|
231
|
+
* A tool whose AI agents are configured by `setupAgents`: maz-ui by default,
|
|
232
|
+
* or another package that ships its own MCP server and rules.
|
|
233
|
+
*/
|
|
234
|
+
interface AgentsTool {
|
|
235
|
+
/** Name of the tool: key of its MCP server, `.claude/rules/<name>.md` and markers of the generated content */
|
|
236
|
+
name: string;
|
|
237
|
+
/** Package that ships the MCP server */
|
|
238
|
+
mcpPackage: string;
|
|
239
|
+
/** Bin of `mcpPackage` that starts the MCP server */
|
|
240
|
+
mcpBin: string;
|
|
241
|
+
/** Arguments of `mcpBin` that start the MCP server (e.g. `['mcp']`). Default `[]` */
|
|
242
|
+
mcpArgs?: string[];
|
|
243
|
+
/** What generates the rules, written in their header (markdown, e.g. `` `npx relizy mcp init` ``) */
|
|
244
|
+
generatedBy: string;
|
|
245
|
+
/** Line written under the title of the rules. Default: `> <name> <version> is installed: these rules match this version.` */
|
|
246
|
+
versionNote?: (version: string) => string;
|
|
247
|
+
}
|
|
248
|
+
declare const MAZ_UI_AGENTS_TOOL: AgentsTool;
|
|
249
|
+
type PackageManager = 'pnpm' | 'yarn' | 'bun' | 'npm';
|
|
250
|
+
/** `true` when the `package.json` of the project declares the MCP package of the tool (`@maz-ui/mcp` by default) */
|
|
251
|
+
declare function installsMcpPackage(rootDir: string, tool?: AgentsTool): boolean;
|
|
252
|
+
/** Package manager of a project: the `packageManager` field, else its lockfile */
|
|
253
|
+
declare function detectPackageManager(rootDir: string): PackageManager;
|
|
254
|
+
/**
|
|
255
|
+
* Command of the MCP server of a tool (maz-ui by default) for a project. When
|
|
256
|
+
* the project installs its package, the package manager starts the installed
|
|
257
|
+
* version in about a second, at the version of the lockfile. Otherwise
|
|
258
|
+
* `npx -y` downloads it, pinned to `version`: a dist-tag (`latest`) makes npx
|
|
259
|
+
* query the registry at every start, which can exceed the start timeout of the
|
|
260
|
+
* agents behind a slow registry.
|
|
261
|
+
*/
|
|
262
|
+
declare function mcpServerCommand(rootDir: string, version?: string, tool?: AgentsTool): McpServerCommand;
|
|
263
|
+
/**
|
|
264
|
+
* `true` when generated rules were edited by hand since they were written:
|
|
265
|
+
* they are kept, a newer version of the rules would overwrite the edits.
|
|
266
|
+
*/
|
|
267
|
+
declare function isEditedManagedContent(content: string | undefined, tool?: AgentsTool): boolean;
|
|
222
268
|
/** Detects the AI agents configured in a project */
|
|
223
269
|
declare function detectAgentTargets(rootDir: string): AgentTarget[];
|
|
224
270
|
interface AgentDocs {
|
|
@@ -233,23 +279,41 @@ interface AgentDocs {
|
|
|
233
279
|
* package installed for the project is found.
|
|
234
280
|
*/
|
|
235
281
|
declare function findInstalledPackage(fromDir: string, name: string): string | undefined;
|
|
236
|
-
/** Reads the agent files shipped in `maz-ui/docs/agents` */
|
|
237
282
|
/** Version of an installed package, read from its `package.json` */
|
|
238
283
|
declare function readPackageVersion(packageDir: string): string | undefined;
|
|
284
|
+
/**
|
|
285
|
+
* Workspace patterns of a monorepo: the `packages` of `pnpm-workspace.yaml`,
|
|
286
|
+
* else the `workspaces` of `package.json` (npm, yarn, bun), else `apps/*` and
|
|
287
|
+
* `packages/*`. Negated patterns are ignored.
|
|
288
|
+
*/
|
|
289
|
+
declare function readWorkspacePatterns(rootDir: string): string[];
|
|
290
|
+
/** Folders of the workspaces of a monorepo, in the order of the patterns. Only the fixed part of each pattern is read (`apps/*` reads `apps`) */
|
|
291
|
+
declare function findWorkspaceDirs(rootDir: string): string[];
|
|
239
292
|
/**
|
|
240
293
|
* Finds a package installed in a project: in the `node_modules` of the
|
|
241
|
-
* project root and of its
|
|
242
|
-
*
|
|
294
|
+
* project root and of its workspaces (monorepos without hoisting), then in
|
|
295
|
+
* the parent folders.
|
|
243
296
|
*/
|
|
244
297
|
declare function findProjectPackage(rootDir: string, name: string): string | undefined;
|
|
298
|
+
/** Reads the agent files shipped in `maz-ui/docs/agents` */
|
|
245
299
|
declare function readAgentDocs(rootDir: string, docsDir?: string): AgentDocs;
|
|
246
300
|
/**
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
|
|
301
|
+
* Writes a temporary file then renames it: a concurrent reader (several Nuxt
|
|
302
|
+
* apps of a monorepo starting together) sees the old or the new file, never a
|
|
303
|
+
* truncated one.
|
|
304
|
+
*/
|
|
305
|
+
declare function writeFileAtomic(path: string, content: string): void;
|
|
306
|
+
/** Compares two semver versions: negative when `a < b`, positive when `a > b`, `0` when equal */
|
|
307
|
+
declare function compareVersions(a: string, b: string): number;
|
|
308
|
+
/** Version of the tool (maz-ui by default) that generated a managed content, read from its header */
|
|
309
|
+
declare function readManagedVersion(content: string | undefined, tool?: AgentsTool): string | undefined;
|
|
310
|
+
/**
|
|
311
|
+
* Configures the AI coding agents of a project to use a tool, maz-ui by
|
|
312
|
+
* default: rules (version matched with the installed tool) and its MCP server.
|
|
313
|
+
* Idempotent and conservative: it only writes files it owns, a delimited
|
|
314
|
+
* section of `AGENTS.md` and its own entry of the MCP config files.
|
|
251
315
|
*/
|
|
252
316
|
declare function setupAgents(options: SetupAgentsOptions): SetupAgentsResult;
|
|
253
317
|
|
|
254
|
-
export { AGENTS_MD_BEGIN, AGENTS_MD_END, AGENT_TARGETS, DEFAULT_MCP_SERVER, MANAGED_MARKER, MCP_SERVER_NAME, createLogger, detectAgentTargets, execPromise, findInstalledPackage, findProjectPackage, logger, printBanner, readAgentDocs, readPackageVersion, redactError, redactSecrets, setupAgents };
|
|
255
|
-
export type { AgentDocs, AgentTarget, ExecPromiseOptions, LogLevel, Logger, LoggerOptions, SetupAgentsAction, SetupAgentsChange, SetupAgentsOptions, SetupAgentsResult };
|
|
318
|
+
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 };
|
|
319
|
+
export type { AgentDocs, AgentTarget, AgentsTool, ExecPromiseOptions, LogLevel, Logger, LoggerOptions, McpServerCommand, PackageManager, SetupAgentsAction, SetupAgentsChange, SetupAgentsOptions, SetupAgentsResult };
|
package/dist/index.mjs
CHANGED
|
@@ -3,8 +3,9 @@ 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
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync, rmSync, readdirSync } from 'node:fs';
|
|
8
|
+
import { join, dirname, basename } from 'node:path';
|
|
8
9
|
import { parse, applyEdits, modify } from 'jsonc-parser';
|
|
9
10
|
|
|
10
11
|
const LogLevelMap = {
|
|
@@ -189,16 +190,93 @@ const AGENTS_MD_BEGIN = "<!-- BEGIN:maz-ui -->";
|
|
|
189
190
|
const AGENTS_MD_END = "<!-- END:maz-ui -->";
|
|
190
191
|
const MCP_SERVER_NAME = "maz-ui";
|
|
191
192
|
const DEFAULT_MCP_SERVER = { command: "npx", args: ["-y", "@maz-ui/mcp@latest"] };
|
|
192
|
-
const
|
|
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
|
+
}
|
|
193
260
|
const CLAUDE_MEMORY_FILES = ["CLAUDE.md", ".claude/CLAUDE.md", "CLAUDE.local.md"];
|
|
194
|
-
function withVersion(content, version) {
|
|
195
|
-
|
|
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}
|
|
196
264
|
|
|
197
|
-
|
|
265
|
+
${note}
|
|
198
266
|
`);
|
|
199
267
|
}
|
|
200
|
-
function
|
|
201
|
-
return
|
|
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;
|
|
202
280
|
}
|
|
203
281
|
function detectAgentTargets(rootDir) {
|
|
204
282
|
const has = (path) => existsSync(join(rootDir, path));
|
|
@@ -229,18 +307,59 @@ function readPackageVersion(packageDir) {
|
|
|
229
307
|
const file = join(packageDir, "package.json");
|
|
230
308
|
return existsSync(file) ? JSON.parse(readFileSync(file, "utf8")).version : void 0;
|
|
231
309
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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);
|
|
240
355
|
}
|
|
241
|
-
}
|
|
356
|
+
};
|
|
357
|
+
visit(base, depth);
|
|
242
358
|
}
|
|
243
|
-
return
|
|
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);
|
|
244
363
|
}
|
|
245
364
|
function readAgentDocs(rootDir, docsDir) {
|
|
246
365
|
let directory = docsDir;
|
|
@@ -264,6 +383,57 @@ function readAgentDocs(rootDir, docsDir) {
|
|
|
264
383
|
agentsMdSection: readFileSync(agentsMdFile, "utf8").trim()
|
|
265
384
|
};
|
|
266
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
|
+
}
|
|
267
437
|
class ChangeSet {
|
|
268
438
|
constructor(rootDir, dryRun) {
|
|
269
439
|
this.rootDir = rootDir;
|
|
@@ -277,16 +447,14 @@ class ChangeSet {
|
|
|
277
447
|
const path = this.absolute(file);
|
|
278
448
|
return existsSync(path) ? readFileSync(path, "utf8") : void 0;
|
|
279
449
|
}
|
|
280
|
-
write(file, content, current) {
|
|
450
|
+
write(file, content, current, reason) {
|
|
281
451
|
if (current === content) {
|
|
282
452
|
this.changes.push({ file, action: "unchanged" });
|
|
283
453
|
return;
|
|
284
454
|
}
|
|
285
|
-
this.changes.push({ file, action: current === void 0 ? "create" : "update" });
|
|
286
|
-
if (!this.dryRun)
|
|
287
|
-
|
|
288
|
-
writeFileSync(this.absolute(file), content);
|
|
289
|
-
}
|
|
455
|
+
this.changes.push({ file, action: current === void 0 ? "create" : "update", ...reason ? { reason } : {} });
|
|
456
|
+
if (!this.dryRun)
|
|
457
|
+
writeFileAtomic(this.absolute(file), content);
|
|
290
458
|
}
|
|
291
459
|
delete(file) {
|
|
292
460
|
this.changes.push({ file, action: "remove" });
|
|
@@ -300,13 +468,23 @@ class ChangeSet {
|
|
|
300
468
|
this.changes.push({ file, action: "unchanged", reason });
|
|
301
469
|
}
|
|
302
470
|
}
|
|
303
|
-
function isOwned(content) {
|
|
304
|
-
return content === void 0 || content.includes(
|
|
471
|
+
function isOwned(content, setup) {
|
|
472
|
+
return content === void 0 || content.includes(setup.marker);
|
|
305
473
|
}
|
|
306
|
-
function syncOwnedFile(changes, file, content) {
|
|
474
|
+
function syncOwnedFile(changes, file, content, version, setup) {
|
|
475
|
+
const { tool } = setup;
|
|
307
476
|
const current = changes.read(file);
|
|
308
|
-
if (!isOwned(current)) {
|
|
309
|
-
changes.skip(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}`);
|
|
310
488
|
return;
|
|
311
489
|
}
|
|
312
490
|
if (content === void 0) {
|
|
@@ -316,16 +494,17 @@ function syncOwnedFile(changes, file, content) {
|
|
|
316
494
|
}
|
|
317
495
|
changes.write(file, content, current);
|
|
318
496
|
}
|
|
319
|
-
function syncAgentsMd(changes, section) {
|
|
497
|
+
function syncAgentsMd(changes, section, version, setup) {
|
|
498
|
+
const { tool, agentsMdBegin, agentsMdEnd } = setup;
|
|
320
499
|
const file = "AGENTS.md";
|
|
321
500
|
const current = changes.read(file);
|
|
322
|
-
const begin = current?.indexOf(
|
|
323
|
-
const end = current?.indexOf(
|
|
501
|
+
const begin = current?.indexOf(agentsMdBegin) ?? -1;
|
|
502
|
+
const end = current?.indexOf(agentsMdEnd) ?? -1;
|
|
324
503
|
const hasBlock = begin !== -1 && end > begin;
|
|
325
504
|
if (section === void 0) {
|
|
326
505
|
if (!current || !hasBlock)
|
|
327
506
|
return;
|
|
328
|
-
const remaining = `${current.slice(0, begin)}${current.slice(end +
|
|
507
|
+
const remaining = `${current.slice(0, begin)}${current.slice(end + agentsMdEnd.length)}`.replace(/\n{3,}/g, "\n\n").trim();
|
|
329
508
|
if (remaining)
|
|
330
509
|
changes.write(file, `${remaining}
|
|
331
510
|
`, current);
|
|
@@ -333,20 +512,30 @@ function syncAgentsMd(changes, section) {
|
|
|
333
512
|
changes.delete(file);
|
|
334
513
|
return;
|
|
335
514
|
}
|
|
336
|
-
const block =
|
|
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}
|
|
337
526
|
|
|
338
527
|
${section}
|
|
339
528
|
|
|
340
|
-
${
|
|
529
|
+
${agentsMdEnd}`;
|
|
341
530
|
if (!current) {
|
|
342
|
-
changes.write(file, `${
|
|
531
|
+
changes.write(file, `${wrapped}
|
|
343
532
|
`, current);
|
|
344
533
|
} else if (hasBlock) {
|
|
345
|
-
changes.write(file, `${current.slice(0, begin)}${
|
|
534
|
+
changes.write(file, `${current.slice(0, begin)}${wrapped}${current.slice(end + agentsMdEnd.length)}`, current);
|
|
346
535
|
} else {
|
|
347
536
|
changes.write(file, `${current.trimEnd()}
|
|
348
537
|
|
|
349
|
-
${
|
|
538
|
+
${wrapped}
|
|
350
539
|
`, current);
|
|
351
540
|
}
|
|
352
541
|
}
|
|
@@ -355,9 +544,10 @@ const MCP_FILES = {
|
|
|
355
544
|
cursor: { file: ".cursor/mcp.json", rootKey: "mcpServers", withType: false },
|
|
356
545
|
vscode: { file: ".vscode/mcp.json", rootKey: "servers", withType: true }
|
|
357
546
|
};
|
|
358
|
-
function
|
|
547
|
+
function referencesToolMcp(server, tool) {
|
|
359
548
|
const serialized = JSON.stringify(server);
|
|
360
|
-
|
|
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));
|
|
361
551
|
}
|
|
362
552
|
function detectFormatting(content) {
|
|
363
553
|
const indent = /^( +|\t)"/m.exec(content)?.[1] ?? " ";
|
|
@@ -366,7 +556,31 @@ function detectFormatting(content) {
|
|
|
366
556
|
function isJsonObject(value) {
|
|
367
557
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
368
558
|
}
|
|
369
|
-
function
|
|
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) {
|
|
370
584
|
const current = changes.read(config.file);
|
|
371
585
|
const errors = [];
|
|
372
586
|
const parsed = current === void 0 ? {} : parse(current, errors, { allowTrailingComma: true });
|
|
@@ -375,12 +589,12 @@ function syncMcpConfig(changes, config, server, remove) {
|
|
|
375
589
|
return;
|
|
376
590
|
}
|
|
377
591
|
const servers = parsed[config.rootKey] ?? {};
|
|
378
|
-
const existing = Object.entries(servers).find(([, value2]) =>
|
|
592
|
+
const existing = Object.entries(servers).find(([, value2]) => referencesToolMcp(value2, tool));
|
|
379
593
|
const base = current ?? "{}\n";
|
|
380
594
|
const formatting = detectFormatting(base);
|
|
381
595
|
if (remove) {
|
|
382
|
-
if (existing?.[0] ===
|
|
383
|
-
const content2 = applyEdits(base, modify(base, [config.rootKey,
|
|
596
|
+
if (existing?.[0] === tool.name) {
|
|
597
|
+
const content2 = applyEdits(base, modify(base, [config.rootKey, tool.name], void 0, { formattingOptions: formatting }));
|
|
384
598
|
const remaining = parse(content2);
|
|
385
599
|
const isEmpty = Object.keys(remaining).length === 1 && Object.keys(remaining[config.rootKey]).length === 0;
|
|
386
600
|
if (isEmpty)
|
|
@@ -391,50 +605,54 @@ function syncMcpConfig(changes, config, server, remove) {
|
|
|
391
605
|
return;
|
|
392
606
|
}
|
|
393
607
|
if (existing) {
|
|
394
|
-
changes
|
|
608
|
+
updateMcpCommand(changes, config, existing, server, tool);
|
|
395
609
|
return;
|
|
396
610
|
}
|
|
397
|
-
if (servers[
|
|
398
|
-
changes.skip(config.file, `a "${
|
|
611
|
+
if (servers[tool.name] !== void 0) {
|
|
612
|
+
changes.skip(config.file, `a "${tool.name}" server already exists with another command: left untouched`);
|
|
399
613
|
return;
|
|
400
614
|
}
|
|
401
615
|
const value = config.withType ? { type: "stdio", ...server } : { ...server };
|
|
402
|
-
const content = applyEdits(base, modify(base, [config.rootKey,
|
|
616
|
+
const content = applyEdits(base, modify(base, [config.rootKey, tool.name], value, { formattingOptions: formatting }));
|
|
403
617
|
changes.write(config.file, content.endsWith("\n") ? content : `${content}
|
|
404
618
|
`, current);
|
|
405
619
|
}
|
|
406
|
-
function syncRules(changes, rootDir, targets, docs) {
|
|
620
|
+
function syncRules(changes, rootDir, targets, docs, setup) {
|
|
407
621
|
const version = docs?.version ?? "";
|
|
408
622
|
const hasClaudeMemory = CLAUDE_MEMORY_FILES.some((file) => existsSync(join(rootDir, file)));
|
|
409
623
|
const claudeReadsAgentsMd = targets.includes("agents-md") && !hasClaudeMemory;
|
|
410
624
|
if (targets.includes("claude")) {
|
|
411
|
-
const rule = docs && !claudeReadsAgentsMd ? `${
|
|
412
|
-
|
|
413
|
-
${withVersion(docs.claudeRule, version)}
|
|
625
|
+
const rule = docs && !claudeReadsAgentsMd ? `${managedContent(version, withVersion(docs.claudeRule, version, setup.tool), setup)}
|
|
414
626
|
` : void 0;
|
|
415
|
-
syncOwnedFile(changes,
|
|
627
|
+
syncOwnedFile(changes, setup.ruleFile, rule, version, setup);
|
|
416
628
|
}
|
|
417
629
|
if (targets.includes("agents-md"))
|
|
418
|
-
syncAgentsMd(changes, docs ?
|
|
419
|
-
|
|
420
|
-
|
|
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);
|
|
421
638
|
}
|
|
422
639
|
function setupAgents(options) {
|
|
423
|
-
const { rootDir, rules = true, mcp = true, dryRun = false, remove = false } = options;
|
|
640
|
+
const { rootDir, rules = true, mcp = true, dryRun = false, remove = false, tool = MAZ_UI_AGENTS_TOOL } = options;
|
|
641
|
+
const setup = resolveTool(tool);
|
|
424
642
|
const targets = options.targets ?? detectAgentTargets(rootDir);
|
|
425
|
-
const docs = remove || !rules ? void 0 :
|
|
643
|
+
const docs = remove || !rules ? void 0 : resolveAgentDocs(options, tool);
|
|
426
644
|
const version = docs?.version ?? "";
|
|
427
645
|
const changes = new ChangeSet(rootDir, dryRun);
|
|
428
|
-
const server = options.mcpServer ??
|
|
646
|
+
const server = options.mcpServer ?? mcpServerCommand(rootDir, options.mcpVersion, tool);
|
|
429
647
|
if (rules || remove)
|
|
430
|
-
syncRules(changes, rootDir, targets, docs);
|
|
648
|
+
syncRules(changes, rootDir, targets, docs, setup);
|
|
431
649
|
if (mcp || remove) {
|
|
432
650
|
for (const target of ["claude", "cursor", "vscode"]) {
|
|
433
651
|
if (targets.includes(target))
|
|
434
|
-
syncMcpConfig(changes, MCP_FILES[target], server, remove);
|
|
652
|
+
syncMcpConfig(changes, MCP_FILES[target], server, remove, tool);
|
|
435
653
|
}
|
|
436
654
|
}
|
|
437
|
-
return { targets, version, changes: changes.changes };
|
|
655
|
+
return { targets, version, changes: changes.changes, mcpServer: server, localMcpServer: !server.args.includes("-y") };
|
|
438
656
|
}
|
|
439
657
|
|
|
440
|
-
export { AGENTS_MD_BEGIN, AGENTS_MD_END, AGENT_TARGETS, DEFAULT_MCP_SERVER, MANAGED_MARKER, MCP_SERVER_NAME, createLogger, detectAgentTargets, execPromise, findInstalledPackage, findProjectPackage, logger, printBanner, readAgentDocs, readPackageVersion, redactError, redactSecrets, setupAgents };
|
|
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 };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maz-ui/node",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.2.0-beta.0",
|
|
5
5
|
"description": "Node utilities for Maz-UI library",
|
|
6
6
|
"author": "Louis Mazel <me@loicmazuel.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -48,7 +48,14 @@
|
|
|
48
48
|
"jsonc-parser": "^3.3.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"
|
|
51
|
+
"@types/node": "^22.20.5",
|
|
52
|
+
"@vitest/coverage-v8": "^5.0.5",
|
|
53
|
+
"cross-env": "^10.1.0",
|
|
54
|
+
"eslint": "^10.13.0",
|
|
55
|
+
"tsx": "^4.23.15",
|
|
56
|
+
"typescript": "^6.0.3",
|
|
57
|
+
"unbuild": "^3.6.1",
|
|
58
|
+
"vitest": "5.0.5"
|
|
52
59
|
},
|
|
53
60
|
"lint-staged": {
|
|
54
61
|
"*.{js,jsx,ts,tsx,mjs,mts,cjs,md,yml,json}": [
|