@everydaydevopsio/ballast 3.0.4 → 3.1.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.
Files changed (34) hide show
  1. package/README.md +9 -7
  2. package/agents/local-dev/content-badges.md +83 -0
  3. package/agents/local-dev/content-env.md +189 -0
  4. package/agents/local-dev/content-license.md +94 -0
  5. package/agents/local-dev/content-mcp.md +64 -0
  6. package/agents/local-dev/templates/claude-header-badges.md +5 -0
  7. package/agents/local-dev/templates/claude-header-license.md +5 -0
  8. package/agents/local-dev/templates/claude-header-mcp.md +5 -0
  9. package/agents/local-dev/templates/claude-header.md +1 -1
  10. package/agents/local-dev/templates/cursor-frontmatter-badges.yaml +8 -0
  11. package/agents/local-dev/templates/cursor-frontmatter-env.yaml +11 -0
  12. package/agents/local-dev/templates/cursor-frontmatter-license.yaml +10 -0
  13. package/agents/local-dev/templates/cursor-frontmatter-mcp.yaml +10 -0
  14. package/agents/local-dev/templates/opencode-frontmatter-badges.yaml +16 -0
  15. package/agents/local-dev/templates/opencode-frontmatter-license.yaml +16 -0
  16. package/agents/local-dev/templates/opencode-frontmatter-mcp.yaml +16 -0
  17. package/agents/logging/content.md +349 -0
  18. package/agents/logging/templates/claude-header.md +5 -0
  19. package/agents/logging/templates/cursor-frontmatter.yaml +11 -0
  20. package/agents/logging/templates/opencode-frontmatter.yaml +22 -0
  21. package/dist/agents.d.ts +1 -1
  22. package/dist/agents.d.ts.map +1 -1
  23. package/dist/agents.js +2 -1
  24. package/dist/agents.js.map +1 -1
  25. package/dist/build.d.ts +16 -11
  26. package/dist/build.d.ts.map +1 -1
  27. package/dist/build.js +70 -25
  28. package/dist/build.js.map +1 -1
  29. package/dist/install.d.ts +5 -0
  30. package/dist/install.d.ts.map +1 -1
  31. package/dist/install.js +27 -15
  32. package/dist/install.js.map +1 -1
  33. package/package.json +10 -10
  34. package/agents/local-dev/content.md +0 -17
@@ -0,0 +1,349 @@
1
+ # Centralized Logging Agent
2
+
3
+ You are a centralized logging specialist for TypeScript/JavaScript applications. Your role is to configure Pino for structured logging with Fluentd as the backend, and to wire up browser-side logging to a Next.js `/api/logs` endpoint.
4
+
5
+ ## Goals
6
+
7
+ - **Server-side**: Configure Pino to send logs to Fluentd for Node.js apps and Next.js API routes.
8
+ - **Browser-side**: Use pino-browser with pino-transmit-http to send console logs, exceptions, `window.onerror`, and `unhandledrejection` to a Next.js `/api/logs` endpoint.
9
+ - **Log levels**: DEBUG for development, ERROR for production (configurable via `NODE_ENV` or `LOG_LEVEL`).
10
+
11
+ ## Your Responsibilities
12
+
13
+ ### 1. Install Dependencies
14
+
15
+ ```bash
16
+ pnpm add pino pino-fluentd pino-transmit-http @fluent-org/logger
17
+ # or: npm install pino pino-fluentd pino-transmit-http @fluent-org/logger
18
+ # or: yarn add pino pino-fluentd pino-transmit-http @fluent-org/logger
19
+ ```
20
+
21
+ - **pino**: Fast JSON logger
22
+ - **pino-fluentd**: CLI transport to pipe Pino output to Fluentd
23
+ - **pino-transmit-http**: Browser transmit to POST logs to an HTTP endpoint
24
+ - **@fluent-org/logger**: Programmatic Fluentd client (for custom transport when piping is not suitable)
25
+
26
+ ### 2. Server-Side: Node.js and Next.js API
27
+
28
+ #### Option A: Pipe to pino-fluentd (recommended for Node.js)
29
+
30
+ Run your app with output piped to pino-fluentd:
31
+
32
+ ```bash
33
+ node server.js 2>&1 | pino-fluentd --host 127.0.0.1 --port 24224 --tag pino
34
+ ```
35
+
36
+ For Next.js API (custom server or standalone):
37
+
38
+ ```bash
39
+ node server.js 2>&1 | pino-fluentd --host 127.0.0.1 --port 24224 --tag nextjs
40
+ ```
41
+
42
+ #### Option B: Custom Fluentd transport (when piping is not possible)
43
+
44
+ `pino-fluentd` is CLI-only. For programmatic use (e.g. Next.js serverless, or when you cannot pipe), create a custom transport:
45
+
46
+ Create `src/lib/pino-fluent-transport.ts`:
47
+
48
+ ```typescript
49
+ import { Writable } from 'node:stream';
50
+ import { FluentClient } from '@fluent-org/logger';
51
+
52
+ export default function build(opts: {
53
+ host?: string;
54
+ port?: number;
55
+ tag?: string;
56
+ }) {
57
+ const host = opts.host ?? '127.0.0.1';
58
+ const port = opts.port ?? 24224;
59
+ const tag = opts.tag ?? 'pino';
60
+
61
+ const client = new FluentClient(tag, {
62
+ socket: { host, port }
63
+ });
64
+
65
+ return new Writable({
66
+ write(chunk: Buffer, _enc, cb) {
67
+ try {
68
+ const obj = JSON.parse(chunk.toString());
69
+ client
70
+ .emit(tag, obj)
71
+ .then(() => cb())
72
+ .catch(() => cb());
73
+ } catch {
74
+ cb();
75
+ }
76
+ },
77
+ final(cb) {
78
+ client.close();
79
+ cb();
80
+ }
81
+ });
82
+ }
83
+ ```
84
+
85
+ Then use it in `lib/logger.ts`:
86
+
87
+ ```typescript
88
+ import pino from 'pino';
89
+ import build from './pino-fluent-transport';
90
+
91
+ const isProd = process.env.NODE_ENV === 'production';
92
+ const logLevel = process.env.LOG_LEVEL ?? (isProd ? 'error' : 'debug');
93
+ const useFluent = process.env.FLUENT_ENABLED === 'true' || isProd;
94
+
95
+ const stream = useFluent
96
+ ? build({
97
+ host: process.env.FLUENT_HOST ?? '127.0.0.1',
98
+ port: Number(process.env.FLUENT_PORT ?? 24224),
99
+ tag: process.env.FLUENT_TAG ?? 'pino'
100
+ })
101
+ : undefined;
102
+
103
+ export const logger = stream
104
+ ? pino({ level: logLevel }, stream)
105
+ : pino({ level: logLevel });
106
+ ```
107
+
108
+ ### 3. Next.js API: `/api/logs` endpoint
109
+
110
+ Create `src/app/api/logs/route.ts` (App Router) or `pages/api/logs.ts` (Pages Router):
111
+
112
+ **App Router (`src/app/api/logs/route.ts`):**
113
+
114
+ ```typescript
115
+ import { NextRequest, NextResponse } from 'next/server';
116
+ import { logger } from '@/lib/logger';
117
+
118
+ export async function POST(request: NextRequest) {
119
+ try {
120
+ const body = await request.json();
121
+ const entries = Array.isArray(body) ? body : [body];
122
+
123
+ for (const entry of entries) {
124
+ const { level, messages, bindings, ...rest } = entry;
125
+ const msg = messages?.[0] ?? JSON.stringify(rest);
126
+ const logFn = level?.value >= 50 ? logger.error : logger.info;
127
+ logFn({ ...bindings, ...rest }, msg);
128
+ }
129
+
130
+ return NextResponse.json({ ok: true }, { status: 200 });
131
+ } catch (err) {
132
+ logger.error({ err }, 'Failed to ingest browser logs');
133
+ return NextResponse.json({ ok: false }, { status: 500 });
134
+ }
135
+ }
136
+ ```
137
+
138
+ **Pages Router (`pages/api/logs.ts`):**
139
+
140
+ ```typescript
141
+ import type { NextApiRequest, NextApiResponse } from 'next';
142
+ import { logger } from '@/lib/logger';
143
+
144
+ export default async function handler(
145
+ req: NextApiRequest,
146
+ res: NextApiResponse
147
+ ) {
148
+ if (req.method !== 'POST') {
149
+ return res.status(405).json({ ok: false });
150
+ }
151
+
152
+ try {
153
+ const body = typeof req.body === 'string' ? JSON.parse(req.body) : req.body;
154
+ const entries = Array.isArray(body) ? body : [body];
155
+
156
+ for (const entry of entries) {
157
+ const { level, messages, bindings, ...rest } = entry;
158
+ const msg = messages?.[0] ?? JSON.stringify(rest);
159
+ const logFn = level?.value >= 50 ? logger.error : logger.info;
160
+ logFn({ ...bindings, ...rest }, msg);
161
+ }
162
+
163
+ return res.status(200).json({ ok: true });
164
+ } catch (err) {
165
+ logger.error({ err }, 'Failed to ingest browser logs');
166
+ return res.status(500).json({ ok: false });
167
+ }
168
+ }
169
+ ```
170
+
171
+ ### 4. Browser-Side: pino-browser with pino-transmit-http
172
+
173
+ Create `src/lib/browser-logger.ts` (or `lib/browser-logger.ts`):
174
+
175
+ ```typescript
176
+ import pino from 'pino';
177
+ import pinoTransmitHttp from 'pino-transmit-http';
178
+
179
+ const isProd = process.env.NODE_ENV === 'production';
180
+ const logLevel =
181
+ process.env.NEXT_PUBLIC_LOG_LEVEL ?? (isProd ? 'error' : 'debug');
182
+
183
+ export const browserLogger = pino({
184
+ level: logLevel,
185
+ browser: {
186
+ transmit: pinoTransmitHttp({
187
+ url: '/api/logs',
188
+ throttle: 500,
189
+ useSendBeacon: true
190
+ })
191
+ }
192
+ });
193
+ ```
194
+
195
+ ### 5. Wire Up Global Error Handlers (Browser)
196
+
197
+ Create `src/lib/init-browser-logging.ts` and import it from your root layout or `_app`:
198
+
199
+ ```typescript
200
+ import { browserLogger } from './browser-logger';
201
+
202
+ export function initBrowserLogging() {
203
+ if (typeof window === 'undefined') return;
204
+
205
+ // Capture uncaught exceptions
206
+ window.onerror = (message, source, lineno, colno, error) => {
207
+ browserLogger.error(
208
+ {
209
+ err: error,
210
+ source,
211
+ lineno,
212
+ colno,
213
+ type: 'window.onerror'
214
+ },
215
+ String(message)
216
+ );
217
+ return false; // allow default handler to run
218
+ };
219
+
220
+ // Capture unhandled promise rejections
221
+ window.addEventListener('unhandledrejection', (event) => {
222
+ browserLogger.error(
223
+ {
224
+ reason: event.reason,
225
+ type: 'unhandledrejection'
226
+ },
227
+ 'Unhandled promise rejection'
228
+ );
229
+ });
230
+ }
231
+ ```
232
+
233
+ **Next.js App Router** – in `src/app/layout.tsx`:
234
+
235
+ ```tsx
236
+ 'use client';
237
+
238
+ import { useEffect } from 'react';
239
+ import { initBrowserLogging } from '@/lib/init-browser-logging';
240
+
241
+ export default function RootLayout({
242
+ children
243
+ }: {
244
+ children: React.ReactNode;
245
+ }) {
246
+ useEffect(() => {
247
+ initBrowserLogging();
248
+ }, []);
249
+
250
+ return (
251
+ <html lang="en">
252
+ <body>{children}</body>
253
+ </html>
254
+ );
255
+ }
256
+ ```
257
+
258
+ **Next.js Pages Router** – in `pages/_app.tsx`:
259
+
260
+ ```tsx
261
+ import { useEffect } from 'react';
262
+ import { initBrowserLogging } from '@/lib/init-browser-logging';
263
+
264
+ export default function App({ Component, pageProps }) {
265
+ useEffect(() => {
266
+ initBrowserLogging();
267
+ }, []);
268
+
269
+ return <Component {...pageProps} />;
270
+ }
271
+ ```
272
+
273
+ ### 6. Use the Browser Logger
274
+
275
+ Replace `console.log` with the browser logger in client components:
276
+
277
+ ```typescript
278
+ import { browserLogger } from '@/lib/browser-logger';
279
+
280
+ // Instead of console.log('User clicked', data):
281
+ browserLogger.debug({ data }, 'User clicked');
282
+
283
+ // Instead of console.error(err):
284
+ browserLogger.error({ err }, 'Something failed');
285
+ ```
286
+
287
+ ### 7. Environment Variables
288
+
289
+ Add to `.env.example`:
290
+
291
+ ```env
292
+ # Log level: trace | debug | info | warn | error | fatal
293
+ # Development defaults to debug, production to error
294
+ LOG_LEVEL=debug
295
+ NEXT_PUBLIC_LOG_LEVEL=debug
296
+
297
+ # Fluentd (server-side)
298
+ FLUENT_HOST=127.0.0.1
299
+ FLUENT_PORT=24224
300
+ FLUENT_TAG=pino
301
+ FLUENT_ENABLED=false
302
+ ```
303
+
304
+ For production, set `FLUENT_ENABLED=true` and configure `FLUENT_HOST` / `FLUENT_PORT` to point to your Fluentd instance.
305
+
306
+ ### 8. Fluentd Configuration (Reference)
307
+
308
+ Minimal Fluentd config to receive logs on port 24224:
309
+
310
+ ```xml
311
+ <source>
312
+ @type forward
313
+ port 24224
314
+ bind 0.0.0.0
315
+ </source>
316
+
317
+ <match pino.**>
318
+ @type stdout
319
+ </match>
320
+ ```
321
+
322
+ Replace `@type stdout` with `@type elasticsearch`, `@type s3`, or another output as needed.
323
+
324
+ ## Implementation Order
325
+
326
+ 1. Install dependencies (pino, pino-fluentd, pino-transmit-http, fluent-logger)
327
+ 2. Create server-side logger (`lib/logger.ts`) with level from NODE_ENV
328
+ 3. Create `/api/logs` route in Next.js
329
+ 4. Create browser logger with pino-transmit-http pointing to `/api/logs`
330
+ 5. Create `initBrowserLogging` and wire `window.onerror` and `unhandledrejection`
331
+ 6. Import `initBrowserLogging` in root layout or `_app`
332
+ 7. Add env vars to `.env.example`
333
+ 8. Document Fluentd setup if deploying
334
+
335
+ ## Log Level Summary
336
+
337
+ | Environment | Default Level |
338
+ | --------------------------------------- | ------------- |
339
+ | Development (NODE_ENV !== 'production') | DEBUG |
340
+ | Production | ERROR |
341
+
342
+ Override with `LOG_LEVEL` (server) or `NEXT_PUBLIC_LOG_LEVEL` (browser).
343
+
344
+ ## Important Notes
345
+
346
+ - Use the **pipe approach** (`node app | pino-fluentd`) when possible; it keeps the app simple and lets pino-fluentd handle Fluentd connection.
347
+ - For Next.js in serverless (Vercel, etc.), piping is not available; use the programmatic transport or custom fluent-logger transport.
348
+ - The `/api/logs` endpoint receives batched JSON arrays from pino-transmit-http; parse and forward to your server logger.
349
+ - `pino-transmit-http` uses `navigator.sendBeacon` on page unload when available, so logs are not lost when the user navigates away.
@@ -0,0 +1,5 @@
1
+ # Centralized Logging Rules
2
+
3
+ These rules provide instructions for configuring Pino with Fluentd (Node.js, Next.js API) and pino-browser with pino-transmit-http to send browser logs to a Next.js /api/logs endpoint.
4
+
5
+ ---
@@ -0,0 +1,11 @@
1
+ ---
2
+ description: 'Centralized logging specialist - configures Pino with Fluentd for Node/Next.js, and pino-browser to /api/logs'
3
+ alwaysApply: false
4
+ globs:
5
+ - '**/lib/logger*.ts'
6
+ - '**/lib/browser-logger*.ts'
7
+ - '**/api/logs/**'
8
+ - '**/api/logs.*'
9
+ - 'package.json'
10
+ - '.env*'
11
+ ---
@@ -0,0 +1,22 @@
1
+ ---
2
+ description: Configures Pino with Fluentd for Node/Next.js and pino-browser to /api/logs
3
+ mode: subagent
4
+ model: anthropic/claude-sonnet-4-20250514
5
+ temperature: 0.2
6
+ tools:
7
+ write: true
8
+ edit: true
9
+ bash: true
10
+ read: true
11
+ glob: true
12
+ grep: true
13
+ permission:
14
+ bash:
15
+ 'git *': ask
16
+ 'npm *': allow
17
+ 'npx *': allow
18
+ 'pnpm *': allow
19
+ 'yarn *': allow
20
+ 'cat *': allow
21
+ '*': ask
22
+ ---
package/dist/agents.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  declare const PACKAGE_ROOT: string;
2
- export declare const AGENT_IDS: readonly ["linting", "local-dev", "cicd", "observability"];
2
+ export declare const AGENT_IDS: readonly ["linting", "local-dev", "cicd", "observability", "logging"];
3
3
  export type AgentId = (typeof AGENT_IDS)[number];
4
4
  /**
5
5
  * Resolve path to an agent directory
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,YAAY,QAA6B,CAAC;AAEhD,eAAO,MAAM,SAAS,4DAKZ,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,EAAE,CAErC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,CAQjE;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,YAAY,QAA6B,CAAC;AAEhD,eAAO,MAAM,SAAS,uEAMZ,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,EAAE,CAErC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,CAQjE;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
package/dist/agents.js CHANGED
@@ -15,7 +15,8 @@ exports.AGENT_IDS = [
15
15
  'linting',
16
16
  'local-dev',
17
17
  'cicd',
18
- 'observability'
18
+ 'observability',
19
+ 'logging'
19
20
  ];
20
21
  /**
21
22
  * Resolve path to an agent directory
@@ -1 +1 @@
1
- {"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":";;;;;;AAeA,kCAEC;AAKD,gCAEC;AAKD,oCAEC;AAKD,sCAQC;AA5CD,gDAAwB;AAExB,MAAM,YAAY,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AA4CvC,oCAAY;AA1CR,QAAA,SAAS,GAAG;IACvB,SAAS;IACT,WAAW;IACX,MAAM;IACN,eAAe;CACP,CAAC;AAGX;;GAEG;AACH,SAAgB,WAAW,CAAC,OAAe;IACzC,OAAO,cAAI,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,SAAgB,UAAU;IACxB,OAAO,iBAAS,CAAC,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,OAAe;IAC1C,OAAQ,iBAA+B,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa,CAAC,MAAyB;IACrD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;QAC/C,IAAI,MAAM;YAAE,OAAO,iBAAS,CAAC,KAAK,EAAE,CAAC;QACrC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,iBAAS,CAAC,KAAK,EAAE,CAAC;IAC/C,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9C,CAAC"}
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":";;;;;;AAgBA,kCAEC;AAKD,gCAEC;AAKD,oCAEC;AAKD,sCAQC;AA7CD,gDAAwB;AAExB,MAAM,YAAY,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AA6CvC,oCAAY;AA3CR,QAAA,SAAS,GAAG;IACvB,SAAS;IACT,WAAW;IACX,MAAM;IACN,eAAe;IACf,SAAS;CACD,CAAC;AAGX;;GAEG;AACH,SAAgB,WAAW,CAAC,OAAe;IACzC,OAAO,cAAI,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,SAAgB,UAAU;IACxB,OAAO,iBAAS,CAAC,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,OAAe;IAC1C,OAAQ,iBAA+B,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa,CAAC,MAAyB;IACrD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;QAC/C,IAAI,MAAM;YAAE,OAAO,iBAAS,CAAC,KAAK,EAAE,CAAC;QACrC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,iBAAS,CAAC,KAAK,EAAE,CAAC;IAC/C,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9C,CAAC"}
package/dist/build.d.ts CHANGED
@@ -1,32 +1,37 @@
1
1
  import type { Target } from './config';
2
2
  /**
3
- * Read agent content.md
3
+ * List rule suffixes for an agent. content.md → suffix ''; content-<suffix>.md → suffix.
4
+ * At least one of content.md or content-*.md must exist.
4
5
  */
5
- export declare function getContent(agentId: string): string;
6
+ export declare function listRuleSuffixes(agentId: string): string[];
6
7
  /**
7
- * Read agent template file
8
+ * Read agent content for a rule. ruleSuffix '' or undefined = content.md; else content-<suffix>.md.
8
9
  */
9
- export declare function getTemplate(agentId: string, filename: string): string;
10
+ export declare function getContent(agentId: string, ruleSuffix?: string): string;
11
+ /**
12
+ * Read agent template file. Tries rule-specific template first (e.g. cursor-frontmatter-mcp.yaml).
13
+ */
14
+ export declare function getTemplate(agentId: string, filename: string, ruleSuffix?: string): string;
10
15
  /**
11
16
  * Build content for Cursor (.mdc = frontmatter + content)
12
17
  */
13
- export declare function buildCursorFormat(agentId: string): string;
18
+ export declare function buildCursorFormat(agentId: string, ruleSuffix?: string): string;
14
19
  /**
15
20
  * Build content for Claude (header + content)
16
21
  */
17
- export declare function buildClaudeFormat(agentId: string): string;
22
+ export declare function buildClaudeFormat(agentId: string, ruleSuffix?: string): string;
18
23
  /**
19
24
  * Build content for OpenCode (YAML frontmatter + content)
20
25
  */
21
- export declare function buildOpenCodeFormat(agentId: string): string;
26
+ export declare function buildOpenCodeFormat(agentId: string, ruleSuffix?: string): string;
22
27
  /**
23
- * Build content for the given agent and target
28
+ * Build content for the given agent, target, and optional rule suffix
24
29
  */
25
- export declare function buildContent(agentId: string, target: Target): string;
30
+ export declare function buildContent(agentId: string, target: Target, ruleSuffix?: string): string;
26
31
  /**
27
- * Get destination path for installed agent file
32
+ * Get destination path for installed agent file. ruleSuffix '' or undefined = main rule; else <agentId>-<suffix>.
28
33
  */
29
- export declare function getDestination(agentId: string, target: Target, projectRoot: string): {
34
+ export declare function getDestination(agentId: string, target: Target, projectRoot: string, ruleSuffix?: string): {
30
35
  dir: string;
31
36
  file: string;
32
37
  };
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAIvC;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOrE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI3D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAWpE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAqB/B;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAEtC"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAQvC;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAyB1D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAUvE;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAeR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAQR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAIR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAQR;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAWR;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAsB/B;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAEtC"}
package/dist/build.js CHANGED
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.listRuleSuffixes = listRuleSuffixes;
6
7
  exports.getContent = getContent;
7
8
  exports.getTemplate = getTemplate;
8
9
  exports.buildCursorFormat = buildCursorFormat;
@@ -15,22 +16,65 @@ const fs_1 = __importDefault(require("fs"));
15
16
  const path_1 = __importDefault(require("path"));
16
17
  const agents_1 = require("./agents");
17
18
  const TARGETS = ['cursor', 'claude', 'opencode'];
19
+ /** Rule file convention: content.md (main) and content-<suffix>.md (e.g. content-mcp.md) */
20
+ const CONTENT_PREFIX = 'content';
21
+ const CONTENT_MAIN = `${CONTENT_PREFIX}.md`;
18
22
  /**
19
- * Read agent content.md
23
+ * List rule suffixes for an agent. content.md → suffix ''; content-<suffix>.md → suffix.
24
+ * At least one of content.md or content-*.md must exist.
20
25
  */
21
- function getContent(agentId) {
26
+ function listRuleSuffixes(agentId) {
22
27
  const dir = (0, agents_1.getAgentDir)(agentId);
23
- const file = path_1.default.join(dir, 'content.md');
28
+ if (!fs_1.default.existsSync(dir)) {
29
+ throw new Error(`Agent "${agentId}" has no content.md or content-*.md`);
30
+ }
31
+ const suffixes = [];
32
+ if (fs_1.default.existsSync(path_1.default.join(dir, CONTENT_MAIN))) {
33
+ suffixes.push('');
34
+ }
35
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
36
+ for (const e of entries) {
37
+ if (!e.isFile() ||
38
+ !e.name.startsWith(CONTENT_PREFIX + '-') ||
39
+ !e.name.endsWith('.md'))
40
+ continue;
41
+ const stem = e.name.slice(0, -3);
42
+ const suffix = stem.slice(CONTENT_PREFIX.length + 1);
43
+ if (suffix)
44
+ suffixes.push(suffix);
45
+ }
46
+ if (suffixes.length === 0) {
47
+ throw new Error(`Agent "${agentId}" has no content.md or content-*.md`);
48
+ }
49
+ return suffixes;
50
+ }
51
+ /**
52
+ * Read agent content for a rule. ruleSuffix '' or undefined = content.md; else content-<suffix>.md.
53
+ */
54
+ function getContent(agentId, ruleSuffix) {
55
+ const dir = (0, agents_1.getAgentDir)(agentId);
56
+ const basename = ruleSuffix
57
+ ? `${CONTENT_PREFIX}-${ruleSuffix}.md`
58
+ : CONTENT_MAIN;
59
+ const file = path_1.default.join(dir, basename);
24
60
  if (!fs_1.default.existsSync(file)) {
25
- throw new Error(`Agent "${agentId}" has no content.md`);
61
+ throw new Error(`Agent "${agentId}" has no ${basename}`);
26
62
  }
27
63
  return fs_1.default.readFileSync(file, 'utf8');
28
64
  }
29
65
  /**
30
- * Read agent template file
66
+ * Read agent template file. Tries rule-specific template first (e.g. cursor-frontmatter-mcp.yaml).
31
67
  */
32
- function getTemplate(agentId, filename) {
68
+ function getTemplate(agentId, filename, ruleSuffix) {
33
69
  const dir = (0, agents_1.getAgentDir)(agentId);
70
+ const base = filename.replace(/\.[^.]+$/, '');
71
+ const ext = path_1.default.extname(filename);
72
+ if (ruleSuffix) {
73
+ const ruleFile = path_1.default.join(dir, 'templates', `${base}-${ruleSuffix}${ext}`);
74
+ if (fs_1.default.existsSync(ruleFile)) {
75
+ return fs_1.default.readFileSync(ruleFile, 'utf8');
76
+ }
77
+ }
34
78
  const file = path_1.default.join(dir, 'templates', filename);
35
79
  if (!fs_1.default.existsSync(file)) {
36
80
  throw new Error(`Agent "${agentId}" missing template: ${filename}`);
@@ -40,61 +84,62 @@ function getTemplate(agentId, filename) {
40
84
  /**
41
85
  * Build content for Cursor (.mdc = frontmatter + content)
42
86
  */
43
- function buildCursorFormat(agentId) {
44
- const frontmatter = getTemplate(agentId, 'cursor-frontmatter.yaml');
45
- const content = getContent(agentId);
87
+ function buildCursorFormat(agentId, ruleSuffix) {
88
+ const frontmatter = getTemplate(agentId, 'cursor-frontmatter.yaml', ruleSuffix);
89
+ const content = getContent(agentId, ruleSuffix);
46
90
  return frontmatter + '\n' + content;
47
91
  }
48
92
  /**
49
93
  * Build content for Claude (header + content)
50
94
  */
51
- function buildClaudeFormat(agentId) {
52
- const header = getTemplate(agentId, 'claude-header.md');
53
- const content = getContent(agentId);
95
+ function buildClaudeFormat(agentId, ruleSuffix) {
96
+ const header = getTemplate(agentId, 'claude-header.md', ruleSuffix);
97
+ const content = getContent(agentId, ruleSuffix);
54
98
  return header + content;
55
99
  }
56
100
  /**
57
101
  * Build content for OpenCode (YAML frontmatter + content)
58
102
  */
59
- function buildOpenCodeFormat(agentId) {
60
- const frontmatter = getTemplate(agentId, 'opencode-frontmatter.yaml');
61
- const content = getContent(agentId);
103
+ function buildOpenCodeFormat(agentId, ruleSuffix) {
104
+ const frontmatter = getTemplate(agentId, 'opencode-frontmatter.yaml', ruleSuffix);
105
+ const content = getContent(agentId, ruleSuffix);
62
106
  return frontmatter + '\n' + content;
63
107
  }
64
108
  /**
65
- * Build content for the given agent and target
109
+ * Build content for the given agent, target, and optional rule suffix
66
110
  */
67
- function buildContent(agentId, target) {
111
+ function buildContent(agentId, target, ruleSuffix) {
68
112
  switch (target) {
69
113
  case 'cursor':
70
- return buildCursorFormat(agentId);
114
+ return buildCursorFormat(agentId, ruleSuffix);
71
115
  case 'claude':
72
- return buildClaudeFormat(agentId);
116
+ return buildClaudeFormat(agentId, ruleSuffix);
73
117
  case 'opencode':
74
- return buildOpenCodeFormat(agentId);
118
+ return buildOpenCodeFormat(agentId, ruleSuffix);
75
119
  default:
76
120
  throw new Error(`Unknown target: ${target}`);
77
121
  }
78
122
  }
79
123
  /**
80
- * Get destination path for installed agent file
124
+ * Get destination path for installed agent file. ruleSuffix '' or undefined = main rule; else <agentId>-<suffix>.
81
125
  */
82
- function getDestination(agentId, target, projectRoot) {
126
+ function getDestination(agentId, target, projectRoot, ruleSuffix) {
83
127
  const root = path_1.default.resolve(projectRoot);
128
+ const basename = ruleSuffix ? `${agentId}-${ruleSuffix}` : agentId;
84
129
  switch (target) {
85
130
  case 'cursor': {
86
131
  const dir = path_1.default.join(root, '.cursor', 'rules');
87
- const file = path_1.default.join(dir, `${agentId}.mdc`);
132
+ const file = path_1.default.join(dir, `${basename}.mdc`);
88
133
  return { dir, file };
89
134
  }
90
135
  case 'claude': {
91
136
  const dir = path_1.default.join(root, '.claude', 'rules');
92
- const file = path_1.default.join(dir, `${agentId}.md`);
137
+ const file = path_1.default.join(dir, `${basename}.md`);
93
138
  return { dir, file };
94
139
  }
95
140
  case 'opencode': {
96
141
  const dir = path_1.default.join(root, '.opencode');
97
- const file = path_1.default.join(dir, `${agentId}.md`);
142
+ const file = path_1.default.join(dir, `${basename}.md`);
98
143
  return { dir, file };
99
144
  }
100
145
  default:
package/dist/build.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":";;;;;AAUA,gCAOC;AAKD,kCAOC;AAKD,8CAIC;AAKD,8CAIC;AAKD,kDAIC;AAKD,oCAWC;AAKD,wCAyBC;AAKD,kCAEC;AA7GD,4CAAoB;AACpB,gDAAwB;AACxB,qCAAuC;AAGvC,MAAM,OAAO,GAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;AAE3D;;GAEG;AACH,SAAgB,UAAU,CAAC,OAAe;IACxC,MAAM,GAAG,GAAG,IAAA,oBAAW,EAAC,OAAO,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC1C,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,UAAU,OAAO,qBAAqB,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,YAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CAAC,OAAe,EAAE,QAAgB;IAC3D,MAAM,GAAG,GAAG,IAAA,oBAAW,EAAC,OAAO,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACnD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,UAAU,OAAO,uBAAuB,QAAQ,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,YAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,OAAe;IAC/C,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,OAAe;IAC/C,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,MAAM,GAAG,OAAO,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAgB,mBAAmB,CAAC,OAAe;IACjD,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,EAAE,2BAA2B,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,OAAe,EAAE,MAAc;IAC1D,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACpC,KAAK,QAAQ;YACX,OAAO,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACpC,KAAK,UAAU;YACb,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACtC;YACE,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAC5B,OAAe,EACf,MAAc,EACd,WAAmB;IAEnB,MAAM,IAAI,GAAG,cAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACvC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,GAAG,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YAChD,MAAM,IAAI,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,MAAM,CAAC,CAAC;YAC9C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QACvB,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,GAAG,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YAChD,MAAM,IAAI,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,KAAK,CAAC,CAAC;YAC7C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QACvB,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,GAAG,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YACzC,MAAM,IAAI,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,KAAK,CAAC,CAAC;YAC7C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QACvB,CAAC;QACD;YACE,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW;IACzB,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}