@everydaydevopsio/ballast 3.0.0 → 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.
- package/README.md +19 -6
- package/agents/local-dev/content-badges.md +83 -0
- package/agents/local-dev/content-env.md +189 -0
- package/agents/local-dev/content-license.md +94 -0
- package/agents/local-dev/content-mcp.md +64 -0
- package/agents/local-dev/templates/claude-header-badges.md +5 -0
- package/agents/local-dev/templates/claude-header-license.md +5 -0
- package/agents/local-dev/templates/claude-header-mcp.md +5 -0
- package/agents/local-dev/templates/claude-header.md +1 -1
- package/agents/local-dev/templates/cursor-frontmatter-badges.yaml +8 -0
- package/agents/local-dev/templates/cursor-frontmatter-env.yaml +11 -0
- package/agents/local-dev/templates/cursor-frontmatter-license.yaml +10 -0
- package/agents/local-dev/templates/cursor-frontmatter-mcp.yaml +10 -0
- package/agents/local-dev/templates/opencode-frontmatter-badges.yaml +16 -0
- package/agents/local-dev/templates/opencode-frontmatter-license.yaml +16 -0
- package/agents/local-dev/templates/opencode-frontmatter-mcp.yaml +16 -0
- package/agents/logging/content.md +349 -0
- package/agents/logging/templates/claude-header.md +5 -0
- package/agents/logging/templates/cursor-frontmatter.yaml +11 -0
- package/agents/logging/templates/opencode-frontmatter.yaml +22 -0
- package/dist/agents.d.ts +1 -1
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +2 -1
- package/dist/agents.js.map +1 -1
- package/dist/build.d.ts +16 -11
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +70 -25
- package/dist/build.js.map +1 -1
- package/dist/install.d.ts +5 -0
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +27 -15
- package/dist/install.js.map +1 -1
- package/package.json +14 -14
- 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,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
|
package/dist/agents.d.ts.map
CHANGED
|
@@ -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,
|
|
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
package/dist/agents.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":";;;;;;
|
|
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
|
-
*
|
|
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
|
|
6
|
+
export declare function listRuleSuffixes(agentId: string): string[];
|
|
6
7
|
/**
|
|
7
|
-
* Read agent
|
|
8
|
+
* Read agent content for a rule. ruleSuffix '' or undefined = content.md; else content-<suffix>.md.
|
|
8
9
|
*/
|
|
9
|
-
export declare function
|
|
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
|
|
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
|
};
|
package/dist/build.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
-
*
|
|
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
|
|
26
|
+
function listRuleSuffixes(agentId) {
|
|
22
27
|
const dir = (0, agents_1.getAgentDir)(agentId);
|
|
23
|
-
|
|
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
|
|
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
|
|
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, `${
|
|
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, `${
|
|
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, `${
|
|
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":";;;;;
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
|