@codedrifters/configulator 0.0.154 → 0.0.155
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/lib/index.d.mts +72 -2
- package/lib/index.d.ts +72 -2
- package/lib/index.js +1352 -733
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1151 -540
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -207,19 +207,20 @@ __export(index_exports, {
|
|
|
207
207
|
Vitest: () => Vitest,
|
|
208
208
|
addApproveMergeUpgradeWorkflow: () => addApproveMergeUpgradeWorkflow,
|
|
209
209
|
addBuildCompleteJob: () => addBuildCompleteJob,
|
|
210
|
-
|
|
210
|
+
awsCdkBundle: () => awsCdkBundle,
|
|
211
|
+
baseBundle: () => baseBundle,
|
|
212
|
+
getLatestEligibleVersion: () => getLatestEligibleVersion,
|
|
213
|
+
jestBundle: () => jestBundle,
|
|
214
|
+
pnpmBundle: () => pnpmBundle,
|
|
215
|
+
projenBundle: () => projenBundle,
|
|
216
|
+
turborepoBundle: () => turborepoBundle,
|
|
217
|
+
typescriptBundle: () => typescriptBundle,
|
|
218
|
+
vitestBundle: () => vitestBundle
|
|
211
219
|
});
|
|
212
220
|
module.exports = __toCommonJS(index_exports);
|
|
213
221
|
|
|
214
222
|
// src/agent/agent-config.ts
|
|
215
|
-
var
|
|
216
|
-
|
|
217
|
-
// src/agent/bundles/index.ts
|
|
218
|
-
var BUILT_IN_BUNDLES = [];
|
|
219
|
-
|
|
220
|
-
// src/agent/renderers/claude-renderer.ts
|
|
221
|
-
var import_projen = require("projen");
|
|
222
|
-
var import_textfile = require("projen/lib/textfile");
|
|
223
|
+
var import_projen7 = require("projen");
|
|
223
224
|
|
|
224
225
|
// src/agent/types.ts
|
|
225
226
|
var AGENT_RULE_SCOPE = {
|
|
@@ -249,87 +250,1142 @@ var MCP_TRANSPORT = {
|
|
|
249
250
|
SSE: "sse"
|
|
250
251
|
};
|
|
251
252
|
|
|
252
|
-
// src/agent/
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
// src/agent/bundles/utils.ts
|
|
254
|
+
function hasComponent(project, ctor) {
|
|
255
|
+
if (project.components.some((c) => c instanceof ctor)) return true;
|
|
256
|
+
return project.subprojects.some(
|
|
257
|
+
(sub) => sub.components.some((c) => c instanceof ctor)
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
function hasDep(project, name) {
|
|
261
|
+
if (project.deps.all.some((d) => d.name === name)) return true;
|
|
262
|
+
return project.subprojects.some(
|
|
263
|
+
(sub) => sub.deps.all.some((d) => d.name === name)
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
function hasFile(project, filename) {
|
|
267
|
+
if (project.tryFindFile(filename) !== void 0) return true;
|
|
268
|
+
return project.subprojects.some(
|
|
269
|
+
(sub) => sub.tryFindFile(filename) !== void 0
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/agent/bundles/aws-cdk.ts
|
|
274
|
+
var awsCdkBundle = {
|
|
275
|
+
name: "aws-cdk",
|
|
276
|
+
description: "AWS CDK construct patterns, L2/L3 conventions, IAM best practices",
|
|
277
|
+
appliesWhen: (project) => hasDep(project, "aws-cdk-lib"),
|
|
278
|
+
rules: [
|
|
279
|
+
{
|
|
280
|
+
name: "aws-cdk-conventions",
|
|
281
|
+
description: "AWS CDK construct patterns and best practices",
|
|
282
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
283
|
+
filePatterns: ["**/*.ts"],
|
|
284
|
+
content: [
|
|
285
|
+
"# AWS CDK Conventions",
|
|
286
|
+
"",
|
|
287
|
+
"## Construct Structure",
|
|
288
|
+
"",
|
|
289
|
+
"- All constructs extend `Construct` from `constructs`",
|
|
290
|
+
"- Use `readonly` for all props interfaces",
|
|
291
|
+
"- Include minimal JSDoc for configuration options",
|
|
292
|
+
"- Follow AWS CDK best practices for resource naming and organization",
|
|
293
|
+
"- Use proper TypeScript types from `aws-cdk-lib`",
|
|
294
|
+
"- Export constructs from `index.ts` for public API",
|
|
295
|
+
"",
|
|
296
|
+
"## CDK Construct Pattern",
|
|
297
|
+
"",
|
|
298
|
+
"```typescript",
|
|
299
|
+
"export interface MyConstructProps {",
|
|
300
|
+
" /** Brief description. */",
|
|
301
|
+
" readonly myProperty: string;",
|
|
302
|
+
"}",
|
|
303
|
+
"",
|
|
304
|
+
"export class MyConstruct extends Construct {",
|
|
305
|
+
" constructor(scope: Construct, id: string, props: MyConstructProps) {",
|
|
306
|
+
" super(scope, id);",
|
|
307
|
+
" // Implementation",
|
|
308
|
+
" }",
|
|
309
|
+
"}",
|
|
310
|
+
"```",
|
|
311
|
+
"",
|
|
312
|
+
"## AWS Best Practices",
|
|
313
|
+
"",
|
|
314
|
+
"- Use AWS CDK v2 (`aws-cdk-lib`)",
|
|
315
|
+
"- Follow AWS best practices for security and resource configuration",
|
|
316
|
+
"- Use proper IAM permissions (principle of least privilege)",
|
|
317
|
+
"- Include proper tags and descriptions for resources",
|
|
318
|
+
"- Use SSM parameters for cross-stack references when needed",
|
|
319
|
+
"- Do not pass values between stacks; use SSM parameters instead",
|
|
320
|
+
"",
|
|
321
|
+
"## CDK Testing",
|
|
322
|
+
"",
|
|
323
|
+
"- Mock `Code.fromAsset` in any test file that synthesizes CDK stacks",
|
|
324
|
+
"- Use static S3 values (`mock-assets-bucket`, `mock-asset-key.zip`) so snapshots are stable",
|
|
325
|
+
"- Add the mock in `beforeAll` and restore in `afterAll`",
|
|
326
|
+
"- Normalize the template before snapshotting when the stack includes asset-based Lambdas"
|
|
327
|
+
].join("\n"),
|
|
328
|
+
tags: ["infrastructure"]
|
|
329
|
+
}
|
|
330
|
+
]
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// src/agent/bundles/base.ts
|
|
334
|
+
var baseBundle = {
|
|
335
|
+
name: "base",
|
|
336
|
+
description: "Core rules: project overview, interaction style, and general coding conventions",
|
|
337
|
+
appliesWhen: () => true,
|
|
338
|
+
rules: [
|
|
339
|
+
{
|
|
340
|
+
name: "project-overview",
|
|
341
|
+
description: "Project context and technology stack overview",
|
|
342
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
343
|
+
content: [
|
|
344
|
+
"# Project Overview",
|
|
345
|
+
"",
|
|
346
|
+
"## Important Notes",
|
|
347
|
+
"",
|
|
348
|
+
"- **Never edit generated files** \u2014 they are marked with `// ~~ Generated by projen`",
|
|
349
|
+
"- **After modifying Projen configuration**, the user should run `npx projen` locally. The agent must not run `npx projen`, `pnpm install`, or `pnpm i`.",
|
|
350
|
+
"- **Configure dependencies through Projen** \u2014 never use `npm install`, `pnpm add`, or `yarn add`. Add them to `deps` or `devDeps` in Projen config.",
|
|
351
|
+
"- **Export from index.ts** to maintain clean public APIs"
|
|
352
|
+
].join("\n"),
|
|
353
|
+
tags: ["project"]
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
name: "interaction-style",
|
|
357
|
+
description: "Interaction style \u2014 ask questions one at a time and wait for feedback",
|
|
358
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
359
|
+
content: [
|
|
360
|
+
"# Interaction Style Guidelines",
|
|
361
|
+
"",
|
|
362
|
+
"When responding to requests, follow these interaction principles.",
|
|
363
|
+
"",
|
|
364
|
+
"1. **Ask questions one at a time**: When clarification is needed, ask a single question and wait for the user's response before proceeding.",
|
|
365
|
+
"2. **Wait for feedback**: After asking a question, pause and wait for the user's answer before asking additional questions or making assumptions.",
|
|
366
|
+
"3. **Avoid question overload**: Do not ask multiple questions in a single response. If multiple clarifications are needed, prioritize the most important question first.",
|
|
367
|
+
"4. **Progressive clarification**: Once the user answers your first question, you may then ask the next most important question if needed.",
|
|
368
|
+
"5. **Confirm understanding**: After receiving feedback, acknowledge the user's response before proceeding with the next step or question.",
|
|
369
|
+
"6. **Be patient**: Do not rush ahead with assumptions. It is better to ask one clarifying question than to proceed with incorrect assumptions."
|
|
370
|
+
].join("\n"),
|
|
371
|
+
tags: ["project"]
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
name: "general-conventions",
|
|
375
|
+
description: "Code formatting (Prettier/ESLint), import conventions (ES modules, import order), error handling (async/await, no floating promises)",
|
|
376
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
377
|
+
filePatterns: ["**/*.ts", "**/*.tsx"],
|
|
378
|
+
content: [
|
|
379
|
+
"# General Conventions",
|
|
380
|
+
"",
|
|
381
|
+
"## Code Formatting",
|
|
382
|
+
"",
|
|
383
|
+
"- Use **Prettier** for formatting (runs automatically on save in VS Code)",
|
|
384
|
+
"- Always use curly braces for control flow, even single-line statements",
|
|
385
|
+
"- Prefer `const` over `let`; avoid `var`",
|
|
386
|
+
"- Use trailing commas in multi-line objects/arrays",
|
|
387
|
+
"",
|
|
388
|
+
"### ESLint Rules to Follow",
|
|
389
|
+
"",
|
|
390
|
+
"- `curly`: Always use curly braces (multi-line, consistent)",
|
|
391
|
+
"- `dot-notation`: Use dot notation over bracket notation",
|
|
392
|
+
"- `no-bitwise`: No bitwise operators",
|
|
393
|
+
"- `@typescript-eslint/no-shadow`: No variable shadowing",
|
|
394
|
+
"- `@typescript-eslint/member-ordering`: Follow member order",
|
|
395
|
+
"",
|
|
396
|
+
"## Import Conventions",
|
|
397
|
+
"",
|
|
398
|
+
"- **Always use ES modules** (`import`/`export`), never `require()`",
|
|
399
|
+
"- Import order:",
|
|
400
|
+
" 1. Built-in Node.js modules (e.g., `node:path`, `node:fs`)",
|
|
401
|
+
" 2. External dependencies (alphabetically sorted)",
|
|
402
|
+
" 3. Internal imports (relative paths)",
|
|
403
|
+
"- Group imports with blank lines between groups",
|
|
404
|
+
"- Alphabetize imports within each group (case-insensitive)",
|
|
405
|
+
"",
|
|
406
|
+
"## Error Handling",
|
|
407
|
+
"",
|
|
408
|
+
"- Always handle promises properly with `await`",
|
|
409
|
+
"- Use `@typescript-eslint/return-await` rule (always return await)",
|
|
410
|
+
"- Never leave floating promises (`@typescript-eslint/no-floating-promises`)",
|
|
411
|
+
"- Use proper error types and meaningful error messages",
|
|
412
|
+
"- Do not swallow errors or use empty catch blocks",
|
|
413
|
+
"- Prefer async/await over raw promises"
|
|
414
|
+
].join("\n"),
|
|
415
|
+
tags: ["coding"]
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
name: "pull-request-conventions",
|
|
419
|
+
description: "Conventional commit PR titles, closing keywords, change summaries",
|
|
420
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
421
|
+
content: [
|
|
422
|
+
"# Pull Request Conventions",
|
|
423
|
+
"",
|
|
424
|
+
"## PR Title Prefix",
|
|
425
|
+
"",
|
|
426
|
+
"**Always** use a **conventional commit prefix** in the PR `title`. Format: `type: description` or `type(scope): description`.",
|
|
427
|
+
"",
|
|
428
|
+
"| Prefix | Use for |",
|
|
429
|
+
"|--------|---------|",
|
|
430
|
+
"| `feat:` | New features or functionality |",
|
|
431
|
+
"| `fix:` | Bug fixes |",
|
|
432
|
+
"| `docs:` | Documentation-only changes |",
|
|
433
|
+
"| `chore:` | Maintenance: deps, tooling, config |",
|
|
434
|
+
"| `refactor:` | Code restructure, no behavior change |",
|
|
435
|
+
"| `release:` | Release preparation, version bumps |",
|
|
436
|
+
"| `hotfix:` | Urgent production fixes |",
|
|
437
|
+
"",
|
|
438
|
+
"## Link to the Issue",
|
|
439
|
+
"",
|
|
440
|
+
"When the PR addresses an issue, **always** include a closing keyword in the PR body:",
|
|
441
|
+
"- `Closes #<issue>`, `Fixes #<issue>`, or `Resolves #<issue>`",
|
|
442
|
+
"",
|
|
443
|
+
"## Summary of Changes",
|
|
444
|
+
"",
|
|
445
|
+
"Every PR must include a **summary of the changes** made. Use bullet points or short paragraphs. Do not leave the description empty.",
|
|
446
|
+
"",
|
|
447
|
+
"## Commit Messages",
|
|
448
|
+
"",
|
|
449
|
+
"Use **conventional commits** for git commit messages: `type: short description`. Do not add AI co-author or attribution."
|
|
450
|
+
].join("\n"),
|
|
451
|
+
tags: ["workflow"]
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
name: "branch-naming-conventions",
|
|
455
|
+
description: "Branch format (type/[issue-]description), create-on-GitHub-then-fetch workflow",
|
|
456
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
457
|
+
content: [
|
|
458
|
+
"# Branch Naming Conventions",
|
|
459
|
+
"",
|
|
460
|
+
"## Format",
|
|
461
|
+
"",
|
|
462
|
+
"```",
|
|
463
|
+
"<type>/[<issue>-]<description>",
|
|
464
|
+
"```",
|
|
465
|
+
"",
|
|
466
|
+
"- **type** (required): One of `feat`, `fix`, `docs`, `chore`, `refactor`, `release`, `hotfix`",
|
|
467
|
+
"- **issue** (optional): Issue number (e.g., `25`). Include when known.",
|
|
468
|
+
"- **description** (required): Short, lowercase, kebab-case summary",
|
|
469
|
+
"",
|
|
470
|
+
"## Examples",
|
|
471
|
+
"",
|
|
472
|
+
"- `feat/25-add-cursor-rules`",
|
|
473
|
+
"- `fix/23-rename-cursor-rules-mdc`",
|
|
474
|
+
"- `chore/upgrade-eslint`",
|
|
475
|
+
"- `docs/update-readme`"
|
|
476
|
+
].join("\n"),
|
|
477
|
+
tags: ["workflow"]
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
name: "issue-conventions",
|
|
481
|
+
description: "Issue title prefixes, GitHub issue type mapping, prerequisite issues",
|
|
482
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
483
|
+
content: [
|
|
484
|
+
"# Issue Title Conventions",
|
|
485
|
+
"",
|
|
486
|
+
"## Format",
|
|
487
|
+
"",
|
|
488
|
+
"```",
|
|
489
|
+
"<type>: <description>",
|
|
490
|
+
"```",
|
|
491
|
+
"",
|
|
492
|
+
"## Types",
|
|
493
|
+
"",
|
|
494
|
+
"| Prefix | Use for |",
|
|
495
|
+
"|--------|---------|",
|
|
496
|
+
"| `epic:` | Large initiatives spanning multiple child issues |",
|
|
497
|
+
"| `feat:` | New features or functionality |",
|
|
498
|
+
"| `fix:` | Bug fixes |",
|
|
499
|
+
"| `chore:` | Maintenance: deps, tooling, config |",
|
|
500
|
+
"| `docs:` | Documentation-only work |",
|
|
501
|
+
"| `refactor:` | Code restructure, no behavior change |",
|
|
502
|
+
"| `release:` | Release preparation, version bumps |",
|
|
503
|
+
"| `hotfix:` | Urgent production fixes |",
|
|
504
|
+
"",
|
|
505
|
+
"## Prerequisite Issues",
|
|
506
|
+
"",
|
|
507
|
+
"Include any prerequisite (blocking) issues in the issue body when they exist.",
|
|
508
|
+
"Use a **Dependencies** section or `**Depends on:** #123`."
|
|
509
|
+
].join("\n"),
|
|
510
|
+
tags: ["workflow"]
|
|
511
|
+
}
|
|
512
|
+
]
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
// src/agent/bundles/jest.ts
|
|
516
|
+
var jestBundle = {
|
|
517
|
+
name: "jest",
|
|
518
|
+
description: "Jest testing conventions and patterns",
|
|
519
|
+
appliesWhen: (project) => hasDep(project, "jest"),
|
|
520
|
+
rules: [
|
|
521
|
+
{
|
|
522
|
+
name: "jest-testing",
|
|
523
|
+
description: "Jest testing conventions and patterns",
|
|
524
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
525
|
+
filePatterns: ["**/*.test.ts", "**/*.spec.ts"],
|
|
526
|
+
content: [
|
|
527
|
+
"# Jest Testing Patterns",
|
|
528
|
+
"",
|
|
529
|
+
"## Mandatory Requirements",
|
|
530
|
+
"",
|
|
531
|
+
"- **Tests MUST be created or updated whenever code functionality is added or changed**",
|
|
532
|
+
"- This applies to all code changes, including:",
|
|
533
|
+
" - New features and functionality",
|
|
534
|
+
" - Bug fixes",
|
|
535
|
+
" - Refactoring that changes behavior",
|
|
536
|
+
" - API changes",
|
|
537
|
+
" - Configuration changes that affect functionality",
|
|
538
|
+
"- Tests should be written or updated as part of the same change that modifies the code",
|
|
539
|
+
"",
|
|
540
|
+
"## Test Structure",
|
|
541
|
+
"",
|
|
542
|
+
"- Use **Jest** with SWC for fast compilation",
|
|
543
|
+
"- Test files: `.spec.ts` or `.test.ts` (co-located with source)",
|
|
544
|
+
"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`",
|
|
545
|
+
"- Prefer snapshot tests for complex object structures",
|
|
546
|
+
"- Mock external dependencies appropriately",
|
|
547
|
+
"",
|
|
548
|
+
"## Test Organization",
|
|
549
|
+
"",
|
|
550
|
+
"- Co-locate test files with source files",
|
|
551
|
+
"- Test files can use dev dependencies (ESLint rule override)",
|
|
552
|
+
"- Use `@swc/jest` for fast compilation",
|
|
553
|
+
"- Configure Jest in `jest.config.json` (not in package.json)",
|
|
554
|
+
"",
|
|
555
|
+
"## Example Test Structure",
|
|
556
|
+
"",
|
|
557
|
+
"```typescript",
|
|
558
|
+
"import { MyClass } from './my-class';",
|
|
559
|
+
"",
|
|
560
|
+
"describe('MyClass', () => {",
|
|
561
|
+
" it('should do something specific', () => {",
|
|
562
|
+
" // Test implementation",
|
|
563
|
+
" });",
|
|
564
|
+
"});",
|
|
565
|
+
"```"
|
|
566
|
+
].join("\n"),
|
|
567
|
+
tags: ["testing"]
|
|
568
|
+
}
|
|
569
|
+
]
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
// src/pnpm/pnpm-workspace.ts
|
|
573
|
+
var import_path = require("path");
|
|
574
|
+
var import_projen = require("projen");
|
|
575
|
+
var MIMIMUM_RELEASE_AGE = {
|
|
576
|
+
ZERO_DAYS: 0,
|
|
577
|
+
ONE_HOUR: 60,
|
|
578
|
+
SIX_HOURS: 360,
|
|
579
|
+
TWELVE_HOURS: 720,
|
|
580
|
+
ONE_DAY: 1440,
|
|
581
|
+
TWO_DAYS: 2880,
|
|
582
|
+
THREE_DAYS: 4320,
|
|
583
|
+
FOUR_DAYS: 5760,
|
|
584
|
+
FIVE_DAYS: 7200,
|
|
585
|
+
SIX_DAYS: 8640,
|
|
586
|
+
ONE_WEEK: 10080
|
|
587
|
+
};
|
|
588
|
+
var PnpmWorkspace = class _PnpmWorkspace extends import_projen.Component {
|
|
255
589
|
/**
|
|
256
|
-
*
|
|
590
|
+
* Get the pnpm workspace component of a project. If it does not exist,
|
|
591
|
+
* return undefined.
|
|
592
|
+
*
|
|
593
|
+
* @param project
|
|
594
|
+
* @returns
|
|
257
595
|
*/
|
|
258
|
-
static
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
_ClaudeRenderer.renderSettings(component, mcpServers, settings);
|
|
262
|
-
_ClaudeRenderer.renderSkills(component, skills);
|
|
263
|
-
_ClaudeRenderer.renderSubAgents(component, subAgents);
|
|
264
|
-
}
|
|
265
|
-
static renderClaudeMd(component, rules) {
|
|
266
|
-
const claudeMdRules = rules.filter((r) => {
|
|
267
|
-
if (r.platforms?.claude?.exclude) return false;
|
|
268
|
-
const target = r.platforms?.claude?.target ?? _ClaudeRenderer.defaultTarget(r);
|
|
269
|
-
return target === CLAUDE_RULE_TARGET.CLAUDE_MD;
|
|
270
|
-
});
|
|
271
|
-
if (claudeMdRules.length === 0) return;
|
|
272
|
-
const lines = [GENERATED_MARKER, ""];
|
|
273
|
-
for (let i = 0; i < claudeMdRules.length; i++) {
|
|
274
|
-
if (i > 0) lines.push("", "---", "");
|
|
275
|
-
lines.push(...claudeMdRules[i].content.split("\n"));
|
|
276
|
-
}
|
|
277
|
-
new import_textfile.TextFile(component, "CLAUDE.md", { lines });
|
|
596
|
+
static of(project) {
|
|
597
|
+
const isDefined = (c) => c instanceof _PnpmWorkspace;
|
|
598
|
+
return project.root.components.find(isDefined);
|
|
278
599
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
600
|
+
constructor(project, options = {}) {
|
|
601
|
+
super(project);
|
|
602
|
+
project.tryFindObjectFile("package.json")?.addDeletionOverride("pnpm");
|
|
603
|
+
this.fileName = options.fileName ?? "pnpm-workspace.yaml";
|
|
604
|
+
this.minimumReleaseAge = options.minimumReleaseAge ?? MIMIMUM_RELEASE_AGE.ONE_DAY;
|
|
605
|
+
this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude ? ["@codedrifters/*", ...options.minimumReleaseAgeExclude] : ["@codedrifters/*"];
|
|
606
|
+
this.onlyBuiltDependencies = options.onlyBuiltDependencies ? options.onlyBuiltDependencies : [];
|
|
607
|
+
this.ignoredBuiltDependencies = options.ignoredBuiltDependencies ? options.ignoredBuiltDependencies : [];
|
|
608
|
+
this.subprojects = options.subprojects ?? [];
|
|
609
|
+
this.defaultCatalog = options.defaultCatalog;
|
|
610
|
+
this.namedCatalogs = options.namedCatalogs;
|
|
611
|
+
project.addPackageIgnore(this.fileName);
|
|
612
|
+
new import_projen.YamlFile(this.project, this.fileName, {
|
|
613
|
+
obj: () => {
|
|
614
|
+
const pnpmConfig = {};
|
|
615
|
+
const packages = new Array();
|
|
616
|
+
for (const subproject of project.subprojects) {
|
|
617
|
+
packages.push((0, import_path.relative)(this.project.outdir, subproject.outdir));
|
|
292
618
|
}
|
|
293
|
-
|
|
294
|
-
|
|
619
|
+
const packageSet = new Set(packages);
|
|
620
|
+
for (const subprojectPath of this.subprojects) {
|
|
621
|
+
packageSet.add(subprojectPath);
|
|
622
|
+
}
|
|
623
|
+
if (this.subprojects.length > 0) {
|
|
624
|
+
packages.length = 0;
|
|
625
|
+
packages.push(...packageSet);
|
|
626
|
+
}
|
|
627
|
+
pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;
|
|
628
|
+
if (this.minimumReleaseAgeExclude.length > 0) {
|
|
629
|
+
pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;
|
|
630
|
+
}
|
|
631
|
+
if (this.onlyBuiltDependencies.length > 0) {
|
|
632
|
+
pnpmConfig.onlyBuiltDependencies = this.onlyBuiltDependencies;
|
|
633
|
+
}
|
|
634
|
+
if (this.ignoredBuiltDependencies.length > 0) {
|
|
635
|
+
pnpmConfig.ignoreBuiltDependencies = this.ignoredBuiltDependencies;
|
|
636
|
+
}
|
|
637
|
+
if (this.defaultCatalog && Object.keys(this.defaultCatalog).length > 0) {
|
|
638
|
+
pnpmConfig.catalog = this.defaultCatalog;
|
|
639
|
+
}
|
|
640
|
+
if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {
|
|
641
|
+
pnpmConfig.namedCatalogs = this.namedCatalogs;
|
|
642
|
+
}
|
|
643
|
+
return {
|
|
644
|
+
...packages.length > 0 ? { packages } : {},
|
|
645
|
+
...pnpmConfig ? { ...pnpmConfig } : {}
|
|
646
|
+
};
|
|
295
647
|
}
|
|
296
|
-
|
|
297
|
-
new import_textfile.TextFile(component, `.claude/rules/${rule.name}.md`, { lines });
|
|
298
|
-
}
|
|
648
|
+
});
|
|
299
649
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
// src/agent/bundles/pnpm.ts
|
|
653
|
+
var pnpmBundle = {
|
|
654
|
+
name: "pnpm",
|
|
655
|
+
description: "PNPM workspace rules and dependency management conventions",
|
|
656
|
+
appliesWhen: (project) => hasComponent(project, PnpmWorkspace),
|
|
657
|
+
rules: [
|
|
658
|
+
{
|
|
659
|
+
name: "pnpm-workspace",
|
|
660
|
+
description: "PNPM workspace and dependency management conventions",
|
|
661
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
662
|
+
filePatterns: ["package.json", "pnpm-workspace.yaml", "pnpm-lock.yaml"],
|
|
663
|
+
content: [
|
|
664
|
+
"# PNPM Workspace Conventions",
|
|
665
|
+
"",
|
|
666
|
+
"## Package Management",
|
|
667
|
+
"",
|
|
668
|
+
"- Use **PNPM** for package management",
|
|
669
|
+
"- Workspace configuration in `pnpm-workspace.yaml`",
|
|
670
|
+
"- Dependencies managed through Projen, not directly in `package.json`",
|
|
671
|
+
"- **Always use workspace dependencies** (`workspace:*` or `workspace:^`) for packages within this monorepo",
|
|
672
|
+
"- Never use published NPM versions of internal packages; always reference the local workspace version",
|
|
673
|
+
"",
|
|
674
|
+
"## Dependency Management",
|
|
675
|
+
"",
|
|
676
|
+
"**DO:**",
|
|
677
|
+
"- Configure dependencies in Projen configuration files (`.projenrc.ts` or `projenrc/*.ts`)",
|
|
678
|
+
"- Add dependencies to `deps`, `devDeps`, or `peerDeps` arrays in project configuration",
|
|
679
|
+
'- Use catalog dependencies when available (e.g., `"aws-cdk-lib@catalog:"`)',
|
|
680
|
+
"- Ask the user to run `npx projen` and `pnpm install` after updating dependency configuration",
|
|
681
|
+
"",
|
|
682
|
+
"**DO NOT:**",
|
|
683
|
+
"- Run `npm install some-package`",
|
|
684
|
+
"- Run `pnpm add some-package`",
|
|
685
|
+
"- Run `yarn add some-package`",
|
|
686
|
+
"- Manually edit `package.json` dependencies",
|
|
687
|
+
"",
|
|
688
|
+
"Manual package installation creates conflicts with Projen-managed files."
|
|
689
|
+
].join("\n"),
|
|
690
|
+
tags: ["workflow"]
|
|
691
|
+
}
|
|
692
|
+
]
|
|
693
|
+
};
|
|
694
|
+
|
|
695
|
+
// src/agent/bundles/projen.ts
|
|
696
|
+
var projenBundle = {
|
|
697
|
+
name: "projen",
|
|
698
|
+
description: "Projen conventions, synthesis workflow, .projenrc.ts patterns",
|
|
699
|
+
appliesWhen: (project) => hasDep(project, "projen"),
|
|
700
|
+
rules: [
|
|
701
|
+
{
|
|
702
|
+
name: "projen-conventions",
|
|
703
|
+
description: "Projen configuration patterns and best practices",
|
|
704
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
705
|
+
filePatterns: ["projenrc/**/*.ts", ".projenrc.ts"],
|
|
706
|
+
content: [
|
|
707
|
+
"# Projen Conventions",
|
|
708
|
+
"",
|
|
709
|
+
"## Configuration Management",
|
|
710
|
+
"",
|
|
711
|
+
"- **Never edit generated files** (`package.json`, `tsconfig.json`, etc. marked with `// ~~ Generated by projen`)",
|
|
712
|
+
"- Edit Projen configuration in:",
|
|
713
|
+
" - `.projenrc.ts` (root)",
|
|
714
|
+
" - `projenrc/*.ts` (package-specific)",
|
|
715
|
+
"- After making Projen changes, ask the user to run `npx projen` locally (agent must not run it)",
|
|
716
|
+
"",
|
|
717
|
+
"## Custom Projen Components",
|
|
718
|
+
"",
|
|
719
|
+
"All custom components must extend `Component` from Projen and use a static `.of()` factory for discovery:",
|
|
720
|
+
"",
|
|
721
|
+
"```typescript",
|
|
722
|
+
"export class MyComponent extends Component {",
|
|
723
|
+
" public static of(project: Project): MyComponent | undefined {",
|
|
724
|
+
" const isDefined = (c: Component): c is MyComponent =>",
|
|
725
|
+
" c instanceof MyComponent;",
|
|
726
|
+
" return project.components.find(isDefined);",
|
|
727
|
+
" }",
|
|
728
|
+
"",
|
|
729
|
+
" constructor(project: Project, options: MyComponentOptions) {",
|
|
730
|
+
" super(project);",
|
|
731
|
+
" // Implementation",
|
|
732
|
+
" }",
|
|
733
|
+
"}",
|
|
734
|
+
"```",
|
|
735
|
+
"",
|
|
736
|
+
"## Component Authoring",
|
|
737
|
+
"",
|
|
738
|
+
"- Export project types and utilities from `index.ts`",
|
|
739
|
+
"- Follow Projen's component lifecycle patterns",
|
|
740
|
+
"- Use `merge` from `ts-deepmerge` for deep merging configuration objects",
|
|
741
|
+
"- Components should be reusable and configurable; use TypeScript interfaces for component options",
|
|
742
|
+
"- Provide sensible defaults while allowing customization",
|
|
743
|
+
"- Document public APIs with minimal JSDoc; put extended documentation in markdown",
|
|
744
|
+
"",
|
|
745
|
+
"## Dependencies",
|
|
746
|
+
"",
|
|
747
|
+
"- Dependencies managed through Projen configuration, not directly in `package.json`",
|
|
748
|
+
'- Use catalog dependencies when available (e.g., `"projen": "catalog:"`)',
|
|
749
|
+
"- Peer dependencies for shared libraries (e.g., `constructs`, `projen`, `aws-cdk-lib`)",
|
|
750
|
+
'- Use workspace protocol for internal packages: `"@org/pkg@workspace:*"`'
|
|
751
|
+
].join("\n"),
|
|
752
|
+
tags: ["workflow"]
|
|
753
|
+
}
|
|
754
|
+
]
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
// src/turbo/turbo-repo.ts
|
|
758
|
+
var import_lib2 = require("projen/lib");
|
|
759
|
+
var import_workflows_model = require("projen/lib/github/workflows-model");
|
|
760
|
+
|
|
761
|
+
// src/turbo/turbo-repo-task.ts
|
|
762
|
+
var import_lib = require("projen/lib");
|
|
763
|
+
var TurboRepoTask = class extends import_lib.Component {
|
|
764
|
+
constructor(project, options) {
|
|
765
|
+
super(project);
|
|
766
|
+
this.project = project;
|
|
767
|
+
this.name = options.name;
|
|
768
|
+
this.dependsOn = options.dependsOn ?? [];
|
|
769
|
+
this.env = options.env ?? [];
|
|
770
|
+
this.passThroughEnv = options.passThroughEnv ?? [];
|
|
771
|
+
this.outputs = options.outputs ?? [];
|
|
772
|
+
this.cache = options.cache ?? true;
|
|
773
|
+
this.inputs = [
|
|
774
|
+
...options.inputs ?? [],
|
|
775
|
+
// rerun if projen config changes
|
|
776
|
+
".projen/**",
|
|
777
|
+
// ignore mac files
|
|
778
|
+
"!.DS_Store",
|
|
779
|
+
"!**/.DS_Store"
|
|
780
|
+
];
|
|
781
|
+
this.outputLogs = options.outputLogs ?? "new-only";
|
|
782
|
+
this.persistent = options.persistent ?? false;
|
|
783
|
+
this.interactive = options.interactive ?? false;
|
|
784
|
+
this.isActive = true;
|
|
785
|
+
}
|
|
786
|
+
taskConfig() {
|
|
787
|
+
return {
|
|
788
|
+
dependsOn: this.dependsOn,
|
|
789
|
+
env: this.env,
|
|
790
|
+
passThroughEnv: this.passThroughEnv,
|
|
791
|
+
outputs: this.outputs,
|
|
792
|
+
cache: this.cache,
|
|
793
|
+
inputs: this.inputs,
|
|
794
|
+
outputLogs: this.outputLogs,
|
|
795
|
+
persistent: this.persistent,
|
|
796
|
+
interactive: this.interactive
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
// src/turbo/turbo-repo.ts
|
|
802
|
+
var ROOT_TURBO_TASK_NAME = "turbo:build";
|
|
803
|
+
var ROOT_CI_TASK_NAME = "build:all";
|
|
804
|
+
var _TurboRepo = class _TurboRepo extends import_lib2.Component {
|
|
805
|
+
constructor(project, options = {}) {
|
|
806
|
+
super(project);
|
|
807
|
+
this.project = project;
|
|
808
|
+
/**
|
|
809
|
+
* Sub-Tasks to run
|
|
810
|
+
*/
|
|
811
|
+
this.tasks = [];
|
|
812
|
+
this.turboVersion = options.turboVersion ?? "catalog:";
|
|
813
|
+
this.isRootProject = project === project.root;
|
|
814
|
+
if (this.isRootProject) {
|
|
815
|
+
project.addDevDeps(`turbo@${this.turboVersion}`);
|
|
306
816
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
817
|
+
project.gitignore.addPatterns("/.turbo");
|
|
818
|
+
project.npmignore?.addPatterns("/.turbo/");
|
|
819
|
+
this.extends = options.extends ?? (this.isRootProject ? [] : ["//"]);
|
|
820
|
+
this.globalDependencies = options.globalDependencies ?? [];
|
|
821
|
+
this.globalEnv = options.globalEnv ?? [];
|
|
822
|
+
this.globalPassThroughEnv = options.globalPassThroughEnv ?? [];
|
|
823
|
+
this.ui = options.ui ?? "stream";
|
|
824
|
+
this.dangerouslyDisablePackageManagerCheck = options.dangerouslyDisablePackageManagerCheck ?? false;
|
|
825
|
+
this.cacheDir = options.cacheDir ?? ".turbo/cache";
|
|
826
|
+
this.daemon = options.daemon ?? true;
|
|
827
|
+
this.envMode = options.envMode ?? "strict";
|
|
828
|
+
this.remoteCacheOptions = options.remoteCacheOptions;
|
|
829
|
+
this.buildAllTaskEnvVars = options.buildAllTaskEnvVars ?? {};
|
|
830
|
+
const rootGeneratedFiles = this.isRootProject ? this.project.components.filter((c) => c instanceof import_lib2.FileBase).map((c) => c.path) : [];
|
|
831
|
+
this.buildTask = new TurboRepoTask(this.project, {
|
|
832
|
+
name: ROOT_TURBO_TASK_NAME,
|
|
833
|
+
dependsOn: this.isRootProject ? [`^${ROOT_TURBO_TASK_NAME}`] : [],
|
|
834
|
+
...rootGeneratedFiles.length > 0 && { inputs: rootGeneratedFiles }
|
|
835
|
+
});
|
|
836
|
+
if (this.isRootProject) {
|
|
837
|
+
this.buildAllTask = this.project.tasks.addTask(ROOT_CI_TASK_NAME, {
|
|
838
|
+
description: "Root build followed by sub-project builds. Mimics the CI build process in one step."
|
|
839
|
+
});
|
|
840
|
+
this.buildAllTask.exec("turbo telemetry disable");
|
|
841
|
+
if (this.buildAllTaskEnvVars) {
|
|
842
|
+
Object.entries(this.buildAllTaskEnvVars).forEach(([name, value]) => {
|
|
843
|
+
this.addGlobalEnvVar(name, value);
|
|
844
|
+
});
|
|
326
845
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
846
|
+
if (!this.remoteCacheOptions) {
|
|
847
|
+
this.buildAllTask.exec(
|
|
848
|
+
`turbo ${ROOT_TURBO_TASK_NAME} --summarize --concurrency=10`
|
|
849
|
+
);
|
|
850
|
+
} else {
|
|
851
|
+
this.buildAllTask.exec(
|
|
852
|
+
`turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,
|
|
853
|
+
{
|
|
854
|
+
condition: '[ ! -n "$CI" ]',
|
|
855
|
+
env: {
|
|
856
|
+
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,
|
|
857
|
+
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
);
|
|
861
|
+
this.buildAllTask.exec(
|
|
862
|
+
`turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,
|
|
863
|
+
{
|
|
864
|
+
condition: '[ -n "$CI" ]',
|
|
865
|
+
env: {
|
|
866
|
+
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text)`,
|
|
867
|
+
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text)`
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
if (!this.isRootProject) {
|
|
874
|
+
const generatedFiles = this.project.components.filter((c) => c instanceof import_lib2.FileBase).map((c) => c.path);
|
|
875
|
+
this.preCompileTask = new TurboRepoTask(project, {
|
|
876
|
+
name: options.preCompileTask?.name ?? "pre-compile",
|
|
877
|
+
inputs: ["src/**", ...generatedFiles]
|
|
878
|
+
});
|
|
879
|
+
this.compileTask = new TurboRepoTask(project, {
|
|
880
|
+
name: options.compileTask?.name ?? "compile",
|
|
881
|
+
inputs: ["src/**", ...generatedFiles]
|
|
882
|
+
});
|
|
883
|
+
this.postCompileTask = new TurboRepoTask(project, {
|
|
884
|
+
name: options.postCompileTask?.name ?? "post-compile",
|
|
885
|
+
inputs: ["src/**", ...generatedFiles]
|
|
886
|
+
});
|
|
887
|
+
this.testTask = new TurboRepoTask(project, {
|
|
888
|
+
name: options.testTask?.name ?? "test"
|
|
889
|
+
});
|
|
890
|
+
this.packageTask = new TurboRepoTask(project, {
|
|
891
|
+
name: options.packageTask?.name ?? "package",
|
|
892
|
+
inputs: [".npmignore"]
|
|
893
|
+
});
|
|
894
|
+
this.tasks.push(
|
|
895
|
+
this.preCompileTask,
|
|
896
|
+
this.compileTask,
|
|
897
|
+
this.postCompileTask,
|
|
898
|
+
this.testTask,
|
|
899
|
+
this.packageTask
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Static method to discovert turbo in a project.
|
|
905
|
+
*/
|
|
906
|
+
static of(project) {
|
|
907
|
+
const isDefined = (c) => c instanceof _TurboRepo;
|
|
908
|
+
return project.components.find(isDefined);
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Add an env var to the global env vars for all tasks.
|
|
912
|
+
* This will also become an input for the build:all task cache at the root.
|
|
913
|
+
*/
|
|
914
|
+
addGlobalEnvVar(name, value) {
|
|
915
|
+
this.buildAllTask?.env(name, value);
|
|
916
|
+
if (this.isRootProject) {
|
|
917
|
+
this.globalEnv.push(name);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Sets GIT_BRANCH_NAME so root tasks (e.g. build:all) pass the current branch.
|
|
922
|
+
* Value must be exactly $(...) so Projen's task runtime expands it; the shell
|
|
923
|
+
* then expands ${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}.
|
|
924
|
+
*/
|
|
925
|
+
activateBranchNameEnvVar() {
|
|
926
|
+
this.addGlobalEnvVar(
|
|
927
|
+
"GIT_BRANCH_NAME",
|
|
928
|
+
'$(echo "${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}")'
|
|
929
|
+
);
|
|
930
|
+
}
|
|
931
|
+
preSynthesize() {
|
|
932
|
+
let nextDependsOn = this.project.deps.all.filter((d) => d.version === "workspace:*").map((d) => [d.name, ROOT_TURBO_TASK_NAME].join("#"));
|
|
933
|
+
if (!this.isRootProject) {
|
|
934
|
+
[
|
|
935
|
+
[this.project.preCompileTask, this.preCompileTask],
|
|
936
|
+
[this.project.compileTask, this.compileTask],
|
|
937
|
+
[this.project.postCompileTask, this.postCompileTask],
|
|
938
|
+
[this.project.testTask, this.testTask],
|
|
939
|
+
[this.project.packageTask, this.packageTask]
|
|
940
|
+
].forEach(([pjTask, turboTask]) => {
|
|
941
|
+
if (pjTask && turboTask && pjTask.steps.length > 0) {
|
|
942
|
+
if (nextDependsOn.length > 0) {
|
|
943
|
+
turboTask.dependsOn.push(...nextDependsOn);
|
|
944
|
+
}
|
|
945
|
+
nextDependsOn = [turboTask.name];
|
|
946
|
+
} else {
|
|
947
|
+
turboTask.isActive = false;
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
this.buildTask.dependsOn.push(...nextDependsOn);
|
|
951
|
+
}
|
|
952
|
+
const fileName = "turbo.json";
|
|
953
|
+
this.project.addPackageIgnore(fileName);
|
|
954
|
+
new import_lib2.JsonFile(this.project, fileName, {
|
|
955
|
+
obj: {
|
|
956
|
+
extends: this.extends.length ? this.extends : void 0,
|
|
957
|
+
globalDependencies: this.isRootProject && this.globalDependencies.length ? this.globalDependencies : void 0,
|
|
958
|
+
globalEnv: this.isRootProject && this.globalEnv.length ? this.globalEnv : void 0,
|
|
959
|
+
globalPassThroughEnv: this.isRootProject && this.globalPassThroughEnv.length ? this.globalPassThroughEnv : void 0,
|
|
960
|
+
ui: this.isRootProject ? this.ui : void 0,
|
|
961
|
+
dangerouslyDisablePackageManagerCheck: this.isRootProject ? this.dangerouslyDisablePackageManagerCheck : void 0,
|
|
962
|
+
cacheDir: this.isRootProject ? this.cacheDir : void 0,
|
|
963
|
+
daemon: this.isRootProject ? this.daemon : void 0,
|
|
964
|
+
envMode: this.isRootProject ? this.envMode : void 0,
|
|
965
|
+
/**
|
|
966
|
+
* All tasks
|
|
967
|
+
*/
|
|
968
|
+
tasks: this.tasks.filter((task) => task.isActive).reduce(
|
|
969
|
+
(acc, task) => {
|
|
970
|
+
acc[task.name] = {
|
|
971
|
+
...task.taskConfig()
|
|
972
|
+
};
|
|
973
|
+
return acc;
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
[this.buildTask.name]: { ...this.buildTask.taskConfig() }
|
|
977
|
+
}
|
|
978
|
+
)
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
super.preSynthesize();
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
_TurboRepo.buildWorkflowOptions = (remoteCacheOptions) => {
|
|
985
|
+
return {
|
|
986
|
+
env: {
|
|
987
|
+
GIT_BRANCH_NAME: "${{ github.head_ref || github.ref_name }}"
|
|
988
|
+
},
|
|
989
|
+
permissions: {
|
|
990
|
+
contents: import_workflows_model.JobPermission.WRITE,
|
|
991
|
+
idToken: import_workflows_model.JobPermission.WRITE
|
|
992
|
+
},
|
|
993
|
+
preBuildSteps: [
|
|
994
|
+
{
|
|
995
|
+
name: "AWS Creds for SSM",
|
|
996
|
+
uses: "aws-actions/configure-aws-credentials@v4",
|
|
997
|
+
with: {
|
|
998
|
+
["role-to-assume"]: remoteCacheOptions.oidcRole,
|
|
999
|
+
["aws-region"]: "us-east-1",
|
|
1000
|
+
["role-duration-seconds"]: "900"
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
]
|
|
1004
|
+
};
|
|
1005
|
+
};
|
|
1006
|
+
var TurboRepo = _TurboRepo;
|
|
1007
|
+
|
|
1008
|
+
// src/agent/bundles/turborepo.ts
|
|
1009
|
+
var turborepoBundle = {
|
|
1010
|
+
name: "turborepo",
|
|
1011
|
+
description: "Turborepo workspace rules and task pipeline conventions",
|
|
1012
|
+
appliesWhen: (project) => hasComponent(project, TurboRepo),
|
|
1013
|
+
rules: [
|
|
1014
|
+
{
|
|
1015
|
+
name: "turborepo-conventions",
|
|
1016
|
+
description: "Turborepo build system and task pipeline conventions",
|
|
1017
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
1018
|
+
filePatterns: ["turbo.json", "package.json"],
|
|
1019
|
+
content: [
|
|
1020
|
+
"# Turborepo Conventions",
|
|
1021
|
+
"",
|
|
1022
|
+
"## Build System",
|
|
1023
|
+
"",
|
|
1024
|
+
"- **Build**: `pnpm build:all` (uses Turborepo)",
|
|
1025
|
+
"- **Test**: `pnpm test` or `pnpm test:watch`",
|
|
1026
|
+
"- **Lint**: `pnpm eslint`",
|
|
1027
|
+
"",
|
|
1028
|
+
"## Task Pipeline",
|
|
1029
|
+
"",
|
|
1030
|
+
"- Uses remote caching (requires AWS credentials)",
|
|
1031
|
+
"- Only rebuilds changed packages",
|
|
1032
|
+
"- Cache key based on file hashes and dependency graph",
|
|
1033
|
+
"- Configured in `turbo.json`",
|
|
1034
|
+
"",
|
|
1035
|
+
"## Workspace Rules",
|
|
1036
|
+
"",
|
|
1037
|
+
"- Source files: `src/` directory",
|
|
1038
|
+
"- Tests: Co-located with source files (`.spec.ts` or `.test.ts`)",
|
|
1039
|
+
"- Exports: Use `index.ts` files for clean public APIs",
|
|
1040
|
+
"- Configuration: Managed by Projen (edit `.projenrc.ts` or `projenrc/*.ts`)"
|
|
1041
|
+
].join("\n"),
|
|
1042
|
+
tags: ["workflow"]
|
|
1043
|
+
}
|
|
1044
|
+
]
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
// src/agent/bundles/typescript.ts
|
|
1048
|
+
var typescriptBundle = {
|
|
1049
|
+
name: "typescript",
|
|
1050
|
+
description: "TypeScript conventions, type safety, naming, JSDoc, member ordering",
|
|
1051
|
+
appliesWhen: (project) => hasFile(project, "tsconfig.json"),
|
|
1052
|
+
rules: [
|
|
1053
|
+
{
|
|
1054
|
+
name: "typescript-conventions",
|
|
1055
|
+
description: "TypeScript coding conventions and style guide",
|
|
1056
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
1057
|
+
filePatterns: ["**/*.ts", "**/*.tsx"],
|
|
1058
|
+
content: [
|
|
1059
|
+
"# TypeScript Conventions",
|
|
1060
|
+
"",
|
|
1061
|
+
"## Type Safety",
|
|
1062
|
+
"",
|
|
1063
|
+
"- Use **strict TypeScript** with all strict checks enabled",
|
|
1064
|
+
"- Always use explicit types; avoid `any` unless absolutely necessary",
|
|
1065
|
+
"- Use `readonly` for immutable properties",
|
|
1066
|
+
"- Prefer interfaces over types for object shapes",
|
|
1067
|
+
"- Use proper TypeScript types from libraries",
|
|
1068
|
+
"",
|
|
1069
|
+
"## Code Organization",
|
|
1070
|
+
"",
|
|
1071
|
+
"- Follow the member ordering rule:",
|
|
1072
|
+
" 1. Public static fields/methods",
|
|
1073
|
+
" 2. Protected static fields/methods",
|
|
1074
|
+
" 3. Private static fields/methods",
|
|
1075
|
+
" 4. Instance fields",
|
|
1076
|
+
" 5. Constructor",
|
|
1077
|
+
" 6. Methods",
|
|
1078
|
+
"",
|
|
1079
|
+
"## Documentation",
|
|
1080
|
+
"",
|
|
1081
|
+
"- **Keep JSDoc minimal** so that the code remains human-readable. Use brief summaries only.",
|
|
1082
|
+
"- Use JSDoc for:",
|
|
1083
|
+
" - Public classes and interfaces (short description)",
|
|
1084
|
+
" - Public methods and properties (brief purpose; parameter and return when not obvious)",
|
|
1085
|
+
" - Configuration options (one-line description)",
|
|
1086
|
+
"- **Extended documentation** belongs in **markdown** files. Link from JSDoc via `@see` or an inline link.",
|
|
1087
|
+
"",
|
|
1088
|
+
"## Naming Conventions",
|
|
1089
|
+
"",
|
|
1090
|
+
"- **Classes**: PascalCase (e.g., `TypeScriptProject`, `StaticHosting`)",
|
|
1091
|
+
"- **Interfaces**: PascalCase, often with `Props` suffix for configuration (e.g., `StaticHostingProps`)",
|
|
1092
|
+
"- **Functions/Methods**: camelCase (e.g., `configureProject`)",
|
|
1093
|
+
"- **Constants**: UPPER_SNAKE_CASE (e.g., `VERSION`, `AWS_STAGE_TYPE`)",
|
|
1094
|
+
"- **Files**: kebab-case for multi-word files (e.g., `aws-deployment-config.ts`)",
|
|
1095
|
+
"- **Private members**: No prefix needed (TypeScript handles visibility)"
|
|
1096
|
+
].join("\n"),
|
|
1097
|
+
tags: ["coding"]
|
|
1098
|
+
}
|
|
1099
|
+
]
|
|
1100
|
+
};
|
|
1101
|
+
|
|
1102
|
+
// src/vitest/vitest-component.ts
|
|
1103
|
+
var import_projen2 = require("projen");
|
|
1104
|
+
var import_javascript = require("projen/lib/javascript");
|
|
1105
|
+
var import_textfile = require("projen/lib/textfile");
|
|
1106
|
+
|
|
1107
|
+
// src/versions.ts
|
|
1108
|
+
var VERSION = {
|
|
1109
|
+
/**
|
|
1110
|
+
* CDK CLI for workflows and command line operations.
|
|
1111
|
+
*
|
|
1112
|
+
* CLI and lib are versioned separately, so this is the CLI version.
|
|
1113
|
+
*/
|
|
1114
|
+
AWS_CDK_CLI_VERSION: "2.1117.0",
|
|
1115
|
+
/**
|
|
1116
|
+
* CDK Version to use for construct projects.
|
|
1117
|
+
*
|
|
1118
|
+
* CLI and lib are versioned separately, so this is the lib version.
|
|
1119
|
+
*/
|
|
1120
|
+
AWS_CDK_LIB_VERSION: "2.248.0",
|
|
1121
|
+
/**
|
|
1122
|
+
* Version of the AWS Constructs library to use.
|
|
1123
|
+
*/
|
|
1124
|
+
AWS_CONSTRUCTS_VERSION: "10.6.0",
|
|
1125
|
+
/**
|
|
1126
|
+
* Version of Node.js to use in CI workflows at github actions.
|
|
1127
|
+
*/
|
|
1128
|
+
NODE_WORKFLOWS: "24",
|
|
1129
|
+
/**
|
|
1130
|
+
* Version of PNPM to use in workflows at github actions.
|
|
1131
|
+
*/
|
|
1132
|
+
PNPM_VERSION: "10.33.0",
|
|
1133
|
+
/**
|
|
1134
|
+
* Version of Projen to use.
|
|
1135
|
+
*/
|
|
1136
|
+
PROJEN_VERSION: "0.99.34",
|
|
1137
|
+
/**
|
|
1138
|
+
* What version of the turborepo library should we use?
|
|
1139
|
+
*/
|
|
1140
|
+
TURBO_VERSION: "2.9.4",
|
|
1141
|
+
/**
|
|
1142
|
+
* What version of Vite to use (pnpm override). Pinned to 5.x so Vitest 4.x
|
|
1143
|
+
* can load config (Vite 6+/7+ are ESM-only; see issue #142). Remove override
|
|
1144
|
+
* when moving to ESM-only test setup.
|
|
1145
|
+
*/
|
|
1146
|
+
VITE_VERSION: "5.4.11",
|
|
1147
|
+
/**
|
|
1148
|
+
* What version of Vitest to use when testRunner is 'vitest'.
|
|
1149
|
+
* Pinned to 3.x so it works with Vite 5 (Vitest 4 requires Vite 6). See issue #142.
|
|
1150
|
+
*/
|
|
1151
|
+
VITEST_VERSION: "3.2.4"
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
// src/vitest/vitest-component.ts
|
|
1155
|
+
var Vitest = class _Vitest extends import_projen2.Component {
|
|
1156
|
+
constructor(project, options = {}) {
|
|
1157
|
+
super(project);
|
|
1158
|
+
this.project = project;
|
|
1159
|
+
this.configFilePath = options.configFilePath ?? "vitest.config.ts";
|
|
1160
|
+
const config = options.config ?? {};
|
|
1161
|
+
this.include = config.include ?? ["**/*.{test,spec}.?(c|m)[jt]s?(x)"];
|
|
1162
|
+
this.exclude = config.exclude ?? [
|
|
1163
|
+
"**/node_modules/**",
|
|
1164
|
+
"**/dist/**",
|
|
1165
|
+
"**/lib/**",
|
|
1166
|
+
"**/.?*"
|
|
1167
|
+
];
|
|
1168
|
+
this.environment = config.environment ?? "node";
|
|
1169
|
+
this.passWithNoTests = config.passWithNoTests ?? true;
|
|
1170
|
+
this.coverageEnabled = config.coverageEnabled ?? true;
|
|
1171
|
+
this.coverageDirectory = config.coverageDirectory ?? "coverage";
|
|
1172
|
+
this.coverageReporters = config.coverageReporters ?? ["text", "lcov"];
|
|
1173
|
+
this.version = options.vitestVersion ?? VERSION.VITEST_VERSION;
|
|
1174
|
+
project.addDevDeps(`vitest@${this.version}`);
|
|
1175
|
+
if (this.coverageEnabled) {
|
|
1176
|
+
project.addDevDeps(`@vitest/coverage-v8@${this.version}`);
|
|
1177
|
+
}
|
|
1178
|
+
const coveragePath = `/${this.coverageDirectory}/`;
|
|
1179
|
+
project.gitignore.addPatterns(coveragePath);
|
|
1180
|
+
project.npmignore?.exclude(coveragePath);
|
|
1181
|
+
this.addTestTasks();
|
|
1182
|
+
this.synthesizeConfig();
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Find the Vitest component on a project.
|
|
1186
|
+
*/
|
|
1187
|
+
static of(project) {
|
|
1188
|
+
const isVitest = (c) => c instanceof _Vitest;
|
|
1189
|
+
return project.components.find(isVitest);
|
|
1190
|
+
}
|
|
1191
|
+
preSynthesize() {
|
|
1192
|
+
super.preSynthesize();
|
|
1193
|
+
for (const component of this.project.components) {
|
|
1194
|
+
if (component instanceof import_javascript.Jest) {
|
|
1195
|
+
throw new Error("Vitest cannot be used together with Jest");
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
addTestTasks() {
|
|
1200
|
+
this.project.testTask.exec("vitest run --update");
|
|
1201
|
+
if (!this.project.tasks.tryFind("test:watch")) {
|
|
1202
|
+
this.project.addTask("test:watch", {
|
|
1203
|
+
description: "Run tests in watch mode",
|
|
1204
|
+
exec: "vitest watch",
|
|
1205
|
+
receiveArgs: true
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
synthesizeConfig() {
|
|
1210
|
+
this.project.tryRemoveFile(this.configFilePath);
|
|
1211
|
+
new import_textfile.TextFile(this, this.configFilePath, {
|
|
1212
|
+
lines: this.renderConfig()
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
renderConfig() {
|
|
1216
|
+
return [
|
|
1217
|
+
'import { defineConfig } from "vitest/config";',
|
|
1218
|
+
"",
|
|
1219
|
+
"export default defineConfig({",
|
|
1220
|
+
" test: {",
|
|
1221
|
+
` include: ${JSON.stringify(this.include)},`,
|
|
1222
|
+
` exclude: ${JSON.stringify(this.exclude)},`,
|
|
1223
|
+
` environment: "${this.environment}",`,
|
|
1224
|
+
` passWithNoTests: ${this.passWithNoTests},`,
|
|
1225
|
+
" coverage: {",
|
|
1226
|
+
` enabled: ${this.coverageEnabled},`,
|
|
1227
|
+
` provider: "v8",`,
|
|
1228
|
+
` reportsDirectory: "${this.coverageDirectory}",`,
|
|
1229
|
+
` reporter: ${JSON.stringify(this.coverageReporters)},`,
|
|
1230
|
+
" },",
|
|
1231
|
+
" },",
|
|
1232
|
+
"});"
|
|
1233
|
+
];
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
// src/agent/bundles/vitest.ts
|
|
1238
|
+
var vitestBundle = {
|
|
1239
|
+
name: "vitest",
|
|
1240
|
+
description: "Vitest testing conventions, patterns, and file scoping",
|
|
1241
|
+
appliesWhen: (project) => hasComponent(project, Vitest),
|
|
1242
|
+
rules: [
|
|
1243
|
+
{
|
|
1244
|
+
name: "vitest-testing",
|
|
1245
|
+
description: "Vitest testing conventions and patterns",
|
|
1246
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
1247
|
+
filePatterns: ["**/*.test.ts", "**/*.spec.ts"],
|
|
1248
|
+
content: [
|
|
1249
|
+
"# Vitest Testing Patterns",
|
|
1250
|
+
"",
|
|
1251
|
+
"## Mandatory Requirements",
|
|
1252
|
+
"",
|
|
1253
|
+
"- **Tests MUST be created or updated whenever code functionality is added or changed**",
|
|
1254
|
+
"- This applies to all code changes, including:",
|
|
1255
|
+
" - New features and functionality",
|
|
1256
|
+
" - Bug fixes",
|
|
1257
|
+
" - Refactoring that changes behavior",
|
|
1258
|
+
" - API changes",
|
|
1259
|
+
" - Configuration changes that affect functionality",
|
|
1260
|
+
"- Tests should be written or updated as part of the same change that modifies the code",
|
|
1261
|
+
"",
|
|
1262
|
+
"## Test Structure",
|
|
1263
|
+
"",
|
|
1264
|
+
"- Use **Vitest** as the test runner",
|
|
1265
|
+
"- Test files: `.spec.ts` or `.test.ts` (co-located with source)",
|
|
1266
|
+
"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`",
|
|
1267
|
+
"- Prefer snapshot tests for complex object structures",
|
|
1268
|
+
"- Mock external dependencies appropriately",
|
|
1269
|
+
"",
|
|
1270
|
+
"## Test Organization",
|
|
1271
|
+
"",
|
|
1272
|
+
"- Co-locate test files with source files",
|
|
1273
|
+
"- Test files can use dev dependencies (ESLint rule override)",
|
|
1274
|
+
"- Import from `vitest`: `import { describe, expect, it } from 'vitest'`",
|
|
1275
|
+
"",
|
|
1276
|
+
"## Example Test Structure",
|
|
1277
|
+
"",
|
|
1278
|
+
"```typescript",
|
|
1279
|
+
"import { describe, expect, it } from 'vitest';",
|
|
1280
|
+
"import { MyClass } from './my-class';",
|
|
1281
|
+
"",
|
|
1282
|
+
"describe('MyClass', () => {",
|
|
1283
|
+
" it('should do something specific', () => {",
|
|
1284
|
+
" // Test implementation",
|
|
1285
|
+
" });",
|
|
1286
|
+
"});",
|
|
1287
|
+
"```"
|
|
1288
|
+
].join("\n"),
|
|
1289
|
+
tags: ["testing"]
|
|
1290
|
+
}
|
|
1291
|
+
]
|
|
1292
|
+
};
|
|
1293
|
+
|
|
1294
|
+
// src/agent/bundles/index.ts
|
|
1295
|
+
var BUILT_IN_BUNDLES = [
|
|
1296
|
+
baseBundle,
|
|
1297
|
+
typescriptBundle,
|
|
1298
|
+
vitestBundle,
|
|
1299
|
+
jestBundle,
|
|
1300
|
+
turborepoBundle,
|
|
1301
|
+
pnpmBundle,
|
|
1302
|
+
awsCdkBundle,
|
|
1303
|
+
projenBundle
|
|
1304
|
+
];
|
|
1305
|
+
|
|
1306
|
+
// src/agent/renderers/claude-renderer.ts
|
|
1307
|
+
var import_projen5 = require("projen");
|
|
1308
|
+
var import_textfile2 = require("projen/lib/textfile");
|
|
1309
|
+
var GENERATED_MARKER = "<!-- ~~ Generated by @codedrifters/configulator. Edits welcome \u2014 please contribute improvements back. ~~ -->";
|
|
1310
|
+
var ClaudeRenderer = class _ClaudeRenderer {
|
|
1311
|
+
/**
|
|
1312
|
+
* Render all Claude Code configuration files.
|
|
1313
|
+
*/
|
|
1314
|
+
static render(component, rules, skills, subAgents, mcpServers, settings) {
|
|
1315
|
+
_ClaudeRenderer.renderClaudeMd(component, rules);
|
|
1316
|
+
_ClaudeRenderer.renderScopedRules(component, rules);
|
|
1317
|
+
_ClaudeRenderer.renderSettings(component, mcpServers, settings);
|
|
1318
|
+
_ClaudeRenderer.renderSkills(component, skills);
|
|
1319
|
+
_ClaudeRenderer.renderSubAgents(component, subAgents);
|
|
1320
|
+
}
|
|
1321
|
+
static renderClaudeMd(component, rules) {
|
|
1322
|
+
const claudeMdRules = rules.filter((r) => {
|
|
1323
|
+
if (r.platforms?.claude?.exclude) return false;
|
|
1324
|
+
const target = r.platforms?.claude?.target ?? _ClaudeRenderer.defaultTarget(r);
|
|
1325
|
+
return target === CLAUDE_RULE_TARGET.CLAUDE_MD;
|
|
1326
|
+
});
|
|
1327
|
+
if (claudeMdRules.length === 0) return;
|
|
1328
|
+
const lines = [GENERATED_MARKER, ""];
|
|
1329
|
+
for (let i = 0; i < claudeMdRules.length; i++) {
|
|
1330
|
+
if (i > 0) lines.push("", "---", "");
|
|
1331
|
+
lines.push(...claudeMdRules[i].content.split("\n"));
|
|
1332
|
+
}
|
|
1333
|
+
new import_textfile2.TextFile(component, "CLAUDE.md", { lines });
|
|
1334
|
+
}
|
|
1335
|
+
static renderScopedRules(component, rules) {
|
|
1336
|
+
const scopedRules = rules.filter((r) => {
|
|
1337
|
+
if (r.platforms?.claude?.exclude) return false;
|
|
1338
|
+
const target = r.platforms?.claude?.target ?? _ClaudeRenderer.defaultTarget(r);
|
|
1339
|
+
return target === CLAUDE_RULE_TARGET.SCOPED_FILE;
|
|
1340
|
+
});
|
|
1341
|
+
for (const rule of scopedRules) {
|
|
1342
|
+
const lines = [];
|
|
1343
|
+
if (rule.filePatterns && rule.filePatterns.length > 0) {
|
|
1344
|
+
lines.push("---");
|
|
1345
|
+
lines.push("paths:");
|
|
1346
|
+
for (const pattern of rule.filePatterns) {
|
|
1347
|
+
lines.push(` - "${pattern}"`);
|
|
1348
|
+
}
|
|
1349
|
+
lines.push("---");
|
|
1350
|
+
lines.push("");
|
|
1351
|
+
}
|
|
1352
|
+
lines.push(...rule.content.split("\n"));
|
|
1353
|
+
new import_textfile2.TextFile(component, `.claude/rules/${rule.name}.md`, { lines });
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
static renderSettings(component, mcpServers, settings) {
|
|
1357
|
+
const obj = {};
|
|
1358
|
+
let hasContent = false;
|
|
1359
|
+
if (settings?.defaultMode) {
|
|
1360
|
+
obj.defaultMode = settings.defaultMode;
|
|
1361
|
+
hasContent = true;
|
|
1362
|
+
}
|
|
1363
|
+
if (settings?.permissions) {
|
|
1364
|
+
const perms = {};
|
|
1365
|
+
if (settings.permissions.allow?.length) {
|
|
1366
|
+
perms.allow = [...settings.permissions.allow];
|
|
1367
|
+
}
|
|
1368
|
+
if (settings.permissions.deny?.length) {
|
|
1369
|
+
perms.deny = [...settings.permissions.deny];
|
|
1370
|
+
}
|
|
1371
|
+
if (settings.permissions.ask?.length) {
|
|
1372
|
+
perms.ask = [...settings.permissions.ask];
|
|
1373
|
+
}
|
|
1374
|
+
if (settings.permissions.additionalDirectories?.length) {
|
|
1375
|
+
perms.additionalDirectories = [
|
|
1376
|
+
...settings.permissions.additionalDirectories
|
|
1377
|
+
];
|
|
1378
|
+
}
|
|
1379
|
+
if (Object.keys(perms).length > 0) {
|
|
1380
|
+
obj.permissions = perms;
|
|
1381
|
+
hasContent = true;
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
if (settings?.hooks) {
|
|
1385
|
+
const hooks = {};
|
|
1386
|
+
for (const [event, entries] of Object.entries(settings.hooks)) {
|
|
1387
|
+
if (entries && entries.length > 0) {
|
|
1388
|
+
hooks[event] = entries;
|
|
333
1389
|
}
|
|
334
1390
|
}
|
|
335
1391
|
if (Object.keys(hooks).length > 0) {
|
|
@@ -409,7 +1465,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
409
1465
|
hasContent = true;
|
|
410
1466
|
}
|
|
411
1467
|
if (!hasContent) return;
|
|
412
|
-
new
|
|
1468
|
+
new import_projen5.JsonFile(component, ".claude/settings.json", { obj });
|
|
413
1469
|
}
|
|
414
1470
|
static buildSandboxObj(sandbox) {
|
|
415
1471
|
const obj = {};
|
|
@@ -485,7 +1541,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
485
1541
|
lines.push("---");
|
|
486
1542
|
lines.push("");
|
|
487
1543
|
lines.push(...skill.instructions.split("\n"));
|
|
488
|
-
new
|
|
1544
|
+
new import_textfile2.TextFile(component, `.claude/skills/${skill.name}/SKILL.md`, {
|
|
489
1545
|
lines
|
|
490
1546
|
});
|
|
491
1547
|
}
|
|
@@ -522,7 +1578,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
522
1578
|
lines.push("---");
|
|
523
1579
|
lines.push("");
|
|
524
1580
|
lines.push(...agent.prompt.split("\n"));
|
|
525
|
-
new
|
|
1581
|
+
new import_textfile2.TextFile(component, `.claude/agents/${agent.name}.md`, { lines });
|
|
526
1582
|
}
|
|
527
1583
|
}
|
|
528
1584
|
/**
|
|
@@ -547,8 +1603,8 @@ var CopilotRenderer = class {
|
|
|
547
1603
|
};
|
|
548
1604
|
|
|
549
1605
|
// src/agent/renderers/cursor-renderer.ts
|
|
550
|
-
var
|
|
551
|
-
var
|
|
1606
|
+
var import_projen6 = require("projen");
|
|
1607
|
+
var import_textfile3 = require("projen/lib/textfile");
|
|
552
1608
|
var GENERATED_MARKER2 = "# ~~ Generated by @codedrifters/configulator. Edits welcome \u2014 please contribute improvements back. ~~";
|
|
553
1609
|
var CursorRenderer = class _CursorRenderer {
|
|
554
1610
|
/**
|
|
@@ -577,7 +1633,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
577
1633
|
lines.push("---");
|
|
578
1634
|
lines.push("");
|
|
579
1635
|
lines.push(...rule.content.split("\n"));
|
|
580
|
-
new
|
|
1636
|
+
new import_textfile3.TextFile(component, `.cursor/rules/${rule.name}.mdc`, { lines });
|
|
581
1637
|
}
|
|
582
1638
|
}
|
|
583
1639
|
static renderSkills(component, skills) {
|
|
@@ -601,7 +1657,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
601
1657
|
lines.push("---");
|
|
602
1658
|
lines.push("");
|
|
603
1659
|
lines.push(...skill.instructions.split("\n"));
|
|
604
|
-
new
|
|
1660
|
+
new import_textfile3.TextFile(component, `.cursor/skills/${skill.name}/SKILL.md`, {
|
|
605
1661
|
lines
|
|
606
1662
|
});
|
|
607
1663
|
}
|
|
@@ -626,7 +1682,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
626
1682
|
lines.push("---");
|
|
627
1683
|
lines.push("");
|
|
628
1684
|
lines.push(...agent.prompt.split("\n"));
|
|
629
|
-
new
|
|
1685
|
+
new import_textfile3.TextFile(component, `.cursor/agents/${agent.name}.md`, { lines });
|
|
630
1686
|
}
|
|
631
1687
|
}
|
|
632
1688
|
static renderMcpServers(component, mcpServers) {
|
|
@@ -642,7 +1698,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
642
1698
|
if (config.env) server.env = { ...config.env };
|
|
643
1699
|
servers[name] = server;
|
|
644
1700
|
}
|
|
645
|
-
new
|
|
1701
|
+
new import_projen6.JsonFile(component, ".cursor/mcp.json", { obj });
|
|
646
1702
|
}
|
|
647
1703
|
static renderHooks(component, settings) {
|
|
648
1704
|
if (!settings?.hooks) return;
|
|
@@ -670,421 +1726,188 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
670
1726
|
command: h.command
|
|
671
1727
|
}));
|
|
672
1728
|
}
|
|
673
|
-
if (beforeReadFile?.length) {
|
|
674
|
-
hooks.beforeReadFile = beforeReadFile.map((h) => ({
|
|
675
|
-
command: h.command
|
|
676
|
-
}));
|
|
677
|
-
}
|
|
678
|
-
if (afterFileEdit?.length) {
|
|
679
|
-
hooks.afterFileEdit = afterFileEdit.map((h) => ({ command: h.command }));
|
|
680
|
-
}
|
|
681
|
-
if (stop?.length) hooks.stop = stop.map((h) => ({ command: h.command }));
|
|
682
|
-
if (Object.keys(hooks).length === 0) return;
|
|
683
|
-
new
|
|
684
|
-
obj: { version: 1, hooks }
|
|
685
|
-
});
|
|
686
|
-
}
|
|
687
|
-
static renderIgnoreFiles(component, settings) {
|
|
688
|
-
if (settings?.ignorePatterns && settings.ignorePatterns.length > 0) {
|
|
689
|
-
new import_textfile2.TextFile(component, ".cursorignore", {
|
|
690
|
-
lines: [GENERATED_MARKER2, "", ...settings.ignorePatterns]
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
if (settings?.indexingIgnorePatterns && settings.indexingIgnorePatterns.length > 0) {
|
|
694
|
-
new import_textfile2.TextFile(component, ".cursorindexingignore", {
|
|
695
|
-
lines: [GENERATED_MARKER2, "", ...settings.indexingIgnorePatterns]
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
// src/agent/agent-config.ts
|
|
702
|
-
var AgentConfig = class _AgentConfig extends import_projen3.Component {
|
|
703
|
-
/**
|
|
704
|
-
* Find the AgentConfig component on a project.
|
|
705
|
-
*/
|
|
706
|
-
static of(project) {
|
|
707
|
-
const isAgentConfig = (c) => c instanceof _AgentConfig;
|
|
708
|
-
return project.components.find(isAgentConfig);
|
|
709
|
-
}
|
|
710
|
-
constructor(project, options = {}) {
|
|
711
|
-
super(project);
|
|
712
|
-
this.options = options;
|
|
713
|
-
}
|
|
714
|
-
preSynthesize() {
|
|
715
|
-
super.preSynthesize();
|
|
716
|
-
const platforms = this.resolvePlatforms();
|
|
717
|
-
const rules = this.resolveRules();
|
|
718
|
-
const skills = this.resolveSkills();
|
|
719
|
-
const subAgents = this.resolveSubAgents();
|
|
720
|
-
const mcpServers = this.options.mcpServers ?? {};
|
|
721
|
-
if (platforms.includes(AGENT_PLATFORM.CURSOR)) {
|
|
722
|
-
CursorRenderer.render(
|
|
723
|
-
this,
|
|
724
|
-
rules,
|
|
725
|
-
skills,
|
|
726
|
-
subAgents,
|
|
727
|
-
mcpServers,
|
|
728
|
-
this.options.cursorSettings
|
|
729
|
-
);
|
|
730
|
-
}
|
|
731
|
-
if (platforms.includes(AGENT_PLATFORM.CLAUDE)) {
|
|
732
|
-
ClaudeRenderer.render(
|
|
733
|
-
this,
|
|
734
|
-
rules,
|
|
735
|
-
skills,
|
|
736
|
-
subAgents,
|
|
737
|
-
mcpServers,
|
|
738
|
-
this.options.claudeSettings
|
|
739
|
-
);
|
|
740
|
-
}
|
|
741
|
-
if (platforms.includes(AGENT_PLATFORM.CODEX)) {
|
|
742
|
-
CodexRenderer.render(this, rules, skills, subAgents);
|
|
743
|
-
}
|
|
744
|
-
if (platforms.includes(AGENT_PLATFORM.COPILOT)) {
|
|
745
|
-
CopilotRenderer.render(this, rules, skills, subAgents);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
resolvePlatforms() {
|
|
749
|
-
return this.options.platforms ?? [AGENT_PLATFORM.CURSOR, AGENT_PLATFORM.CLAUDE];
|
|
750
|
-
}
|
|
751
|
-
resolveRules() {
|
|
752
|
-
const ruleMap = /* @__PURE__ */ new Map();
|
|
753
|
-
if (this.options.autoDetectBundles !== false) {
|
|
754
|
-
for (const bundle of BUILT_IN_BUNDLES) {
|
|
755
|
-
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
756
|
-
if (bundle.appliesWhen(this.project)) {
|
|
757
|
-
for (const rule of bundle.rules) {
|
|
758
|
-
ruleMap.set(rule.name, rule);
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
if (this.options.includeBundles) {
|
|
764
|
-
for (const bundleName of this.options.includeBundles) {
|
|
765
|
-
const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);
|
|
766
|
-
if (bundle) {
|
|
767
|
-
for (const rule of bundle.rules) {
|
|
768
|
-
ruleMap.set(rule.name, rule);
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
if (this.options.rules) {
|
|
774
|
-
for (const rule of this.options.rules) {
|
|
775
|
-
ruleMap.set(rule.name, rule);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
if (this.options.excludeRules) {
|
|
779
|
-
for (const name of this.options.excludeRules) {
|
|
780
|
-
ruleMap.delete(name);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
return [...ruleMap.values()].sort((a, b) => {
|
|
784
|
-
if (a.name === "project-overview") return -1;
|
|
785
|
-
if (b.name === "project-overview") return 1;
|
|
786
|
-
const tagA = a.tags?.[0] ?? "\uFFFF";
|
|
787
|
-
const tagB = b.tags?.[0] ?? "\uFFFF";
|
|
788
|
-
if (tagA !== tagB) return tagA.localeCompare(tagB);
|
|
789
|
-
return a.name.localeCompare(b.name);
|
|
790
|
-
});
|
|
791
|
-
}
|
|
792
|
-
resolveSkills() {
|
|
793
|
-
const skillMap = /* @__PURE__ */ new Map();
|
|
794
|
-
if (this.options.autoDetectBundles !== false) {
|
|
795
|
-
for (const bundle of BUILT_IN_BUNDLES) {
|
|
796
|
-
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
797
|
-
if (bundle.appliesWhen(this.project) && bundle.skills) {
|
|
798
|
-
for (const skill of bundle.skills) {
|
|
799
|
-
skillMap.set(skill.name, skill);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
if (this.options.skills) {
|
|
805
|
-
for (const skill of this.options.skills) {
|
|
806
|
-
skillMap.set(skill.name, skill);
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
return [...skillMap.values()];
|
|
810
|
-
}
|
|
811
|
-
resolveSubAgents() {
|
|
812
|
-
const agentMap = /* @__PURE__ */ new Map();
|
|
813
|
-
if (this.options.autoDetectBundles !== false) {
|
|
814
|
-
for (const bundle of BUILT_IN_BUNDLES) {
|
|
815
|
-
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
816
|
-
if (bundle.appliesWhen(this.project) && bundle.subAgents) {
|
|
817
|
-
for (const agent of bundle.subAgents) {
|
|
818
|
-
agentMap.set(agent.name, agent);
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
if (this.options.subAgents) {
|
|
824
|
-
for (const agent of this.options.subAgents) {
|
|
825
|
-
agentMap.set(agent.name, agent);
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
return [...agentMap.values()];
|
|
829
|
-
}
|
|
830
|
-
};
|
|
831
|
-
|
|
832
|
-
// src/aws/aws-deployment-config.ts
|
|
833
|
-
var import_node_path = require("path");
|
|
834
|
-
var import_utils = __toESM(require_lib());
|
|
835
|
-
var import_projen4 = require("projen");
|
|
836
|
-
|
|
837
|
-
// src/turbo/turbo-repo-task.ts
|
|
838
|
-
var import_lib = require("projen/lib");
|
|
839
|
-
var TurboRepoTask = class extends import_lib.Component {
|
|
840
|
-
constructor(project, options) {
|
|
841
|
-
super(project);
|
|
842
|
-
this.project = project;
|
|
843
|
-
this.name = options.name;
|
|
844
|
-
this.dependsOn = options.dependsOn ?? [];
|
|
845
|
-
this.env = options.env ?? [];
|
|
846
|
-
this.passThroughEnv = options.passThroughEnv ?? [];
|
|
847
|
-
this.outputs = options.outputs ?? [];
|
|
848
|
-
this.cache = options.cache ?? true;
|
|
849
|
-
this.inputs = [
|
|
850
|
-
...options.inputs ?? [],
|
|
851
|
-
// rerun if projen config changes
|
|
852
|
-
".projen/**",
|
|
853
|
-
// ignore mac files
|
|
854
|
-
"!.DS_Store",
|
|
855
|
-
"!**/.DS_Store"
|
|
856
|
-
];
|
|
857
|
-
this.outputLogs = options.outputLogs ?? "new-only";
|
|
858
|
-
this.persistent = options.persistent ?? false;
|
|
859
|
-
this.interactive = options.interactive ?? false;
|
|
860
|
-
this.isActive = true;
|
|
861
|
-
}
|
|
862
|
-
taskConfig() {
|
|
863
|
-
return {
|
|
864
|
-
dependsOn: this.dependsOn,
|
|
865
|
-
env: this.env,
|
|
866
|
-
passThroughEnv: this.passThroughEnv,
|
|
867
|
-
outputs: this.outputs,
|
|
868
|
-
cache: this.cache,
|
|
869
|
-
inputs: this.inputs,
|
|
870
|
-
outputLogs: this.outputLogs,
|
|
871
|
-
persistent: this.persistent,
|
|
872
|
-
interactive: this.interactive
|
|
873
|
-
};
|
|
874
|
-
}
|
|
875
|
-
};
|
|
876
|
-
|
|
877
|
-
// src/turbo/turbo-repo.ts
|
|
878
|
-
var import_lib2 = require("projen/lib");
|
|
879
|
-
var import_workflows_model = require("projen/lib/github/workflows-model");
|
|
880
|
-
var ROOT_TURBO_TASK_NAME = "turbo:build";
|
|
881
|
-
var ROOT_CI_TASK_NAME = "build:all";
|
|
882
|
-
var _TurboRepo = class _TurboRepo extends import_lib2.Component {
|
|
883
|
-
constructor(project, options = {}) {
|
|
884
|
-
super(project);
|
|
885
|
-
this.project = project;
|
|
886
|
-
/**
|
|
887
|
-
* Sub-Tasks to run
|
|
888
|
-
*/
|
|
889
|
-
this.tasks = [];
|
|
890
|
-
this.turboVersion = options.turboVersion ?? "catalog:";
|
|
891
|
-
this.isRootProject = project === project.root;
|
|
892
|
-
if (this.isRootProject) {
|
|
893
|
-
project.addDevDeps(`turbo@${this.turboVersion}`);
|
|
894
|
-
}
|
|
895
|
-
project.gitignore.addPatterns("/.turbo");
|
|
896
|
-
project.npmignore?.addPatterns("/.turbo/");
|
|
897
|
-
this.extends = options.extends ?? (this.isRootProject ? [] : ["//"]);
|
|
898
|
-
this.globalDependencies = options.globalDependencies ?? [];
|
|
899
|
-
this.globalEnv = options.globalEnv ?? [];
|
|
900
|
-
this.globalPassThroughEnv = options.globalPassThroughEnv ?? [];
|
|
901
|
-
this.ui = options.ui ?? "stream";
|
|
902
|
-
this.dangerouslyDisablePackageManagerCheck = options.dangerouslyDisablePackageManagerCheck ?? false;
|
|
903
|
-
this.cacheDir = options.cacheDir ?? ".turbo/cache";
|
|
904
|
-
this.daemon = options.daemon ?? true;
|
|
905
|
-
this.envMode = options.envMode ?? "strict";
|
|
906
|
-
this.remoteCacheOptions = options.remoteCacheOptions;
|
|
907
|
-
this.buildAllTaskEnvVars = options.buildAllTaskEnvVars ?? {};
|
|
908
|
-
const rootGeneratedFiles = this.isRootProject ? this.project.components.filter((c) => c instanceof import_lib2.FileBase).map((c) => c.path) : [];
|
|
909
|
-
this.buildTask = new TurboRepoTask(this.project, {
|
|
910
|
-
name: ROOT_TURBO_TASK_NAME,
|
|
911
|
-
dependsOn: this.isRootProject ? [`^${ROOT_TURBO_TASK_NAME}`] : [],
|
|
912
|
-
...rootGeneratedFiles.length > 0 && { inputs: rootGeneratedFiles }
|
|
1729
|
+
if (beforeReadFile?.length) {
|
|
1730
|
+
hooks.beforeReadFile = beforeReadFile.map((h) => ({
|
|
1731
|
+
command: h.command
|
|
1732
|
+
}));
|
|
1733
|
+
}
|
|
1734
|
+
if (afterFileEdit?.length) {
|
|
1735
|
+
hooks.afterFileEdit = afterFileEdit.map((h) => ({ command: h.command }));
|
|
1736
|
+
}
|
|
1737
|
+
if (stop?.length) hooks.stop = stop.map((h) => ({ command: h.command }));
|
|
1738
|
+
if (Object.keys(hooks).length === 0) return;
|
|
1739
|
+
new import_projen6.JsonFile(component, ".cursor/hooks.json", {
|
|
1740
|
+
obj: { version: 1, hooks }
|
|
913
1741
|
});
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1742
|
+
}
|
|
1743
|
+
static renderIgnoreFiles(component, settings) {
|
|
1744
|
+
if (settings?.ignorePatterns && settings.ignorePatterns.length > 0) {
|
|
1745
|
+
new import_textfile3.TextFile(component, ".cursorignore", {
|
|
1746
|
+
lines: [GENERATED_MARKER2, "", ...settings.ignorePatterns]
|
|
917
1747
|
});
|
|
918
|
-
this.buildAllTask.exec("turbo telemetry disable");
|
|
919
|
-
if (this.buildAllTaskEnvVars) {
|
|
920
|
-
Object.entries(this.buildAllTaskEnvVars).forEach(([name, value]) => {
|
|
921
|
-
this.addGlobalEnvVar(name, value);
|
|
922
|
-
});
|
|
923
|
-
}
|
|
924
|
-
if (!this.remoteCacheOptions) {
|
|
925
|
-
this.buildAllTask.exec(
|
|
926
|
-
`turbo ${ROOT_TURBO_TASK_NAME} --summarize --concurrency=10`
|
|
927
|
-
);
|
|
928
|
-
} else {
|
|
929
|
-
this.buildAllTask.exec(
|
|
930
|
-
`turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,
|
|
931
|
-
{
|
|
932
|
-
condition: '[ ! -n "$CI" ]',
|
|
933
|
-
env: {
|
|
934
|
-
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,
|
|
935
|
-
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
);
|
|
939
|
-
this.buildAllTask.exec(
|
|
940
|
-
`turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,
|
|
941
|
-
{
|
|
942
|
-
condition: '[ -n "$CI" ]',
|
|
943
|
-
env: {
|
|
944
|
-
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text)`,
|
|
945
|
-
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text)`
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
);
|
|
949
|
-
}
|
|
950
1748
|
}
|
|
951
|
-
if (
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
name: options.preCompileTask?.name ?? "pre-compile",
|
|
955
|
-
inputs: ["src/**", ...generatedFiles]
|
|
956
|
-
});
|
|
957
|
-
this.compileTask = new TurboRepoTask(project, {
|
|
958
|
-
name: options.compileTask?.name ?? "compile",
|
|
959
|
-
inputs: ["src/**", ...generatedFiles]
|
|
960
|
-
});
|
|
961
|
-
this.postCompileTask = new TurboRepoTask(project, {
|
|
962
|
-
name: options.postCompileTask?.name ?? "post-compile",
|
|
963
|
-
inputs: ["src/**", ...generatedFiles]
|
|
964
|
-
});
|
|
965
|
-
this.testTask = new TurboRepoTask(project, {
|
|
966
|
-
name: options.testTask?.name ?? "test"
|
|
967
|
-
});
|
|
968
|
-
this.packageTask = new TurboRepoTask(project, {
|
|
969
|
-
name: options.packageTask?.name ?? "package",
|
|
970
|
-
inputs: [".npmignore"]
|
|
1749
|
+
if (settings?.indexingIgnorePatterns && settings.indexingIgnorePatterns.length > 0) {
|
|
1750
|
+
new import_textfile3.TextFile(component, ".cursorindexingignore", {
|
|
1751
|
+
lines: [GENERATED_MARKER2, "", ...settings.indexingIgnorePatterns]
|
|
971
1752
|
});
|
|
972
|
-
this.tasks.push(
|
|
973
|
-
this.preCompileTask,
|
|
974
|
-
this.compileTask,
|
|
975
|
-
this.postCompileTask,
|
|
976
|
-
this.testTask,
|
|
977
|
-
this.packageTask
|
|
978
|
-
);
|
|
979
1753
|
}
|
|
980
1754
|
}
|
|
1755
|
+
};
|
|
1756
|
+
|
|
1757
|
+
// src/agent/agent-config.ts
|
|
1758
|
+
var AgentConfig = class _AgentConfig extends import_projen7.Component {
|
|
981
1759
|
/**
|
|
982
|
-
*
|
|
1760
|
+
* Find the AgentConfig component on a project.
|
|
983
1761
|
*/
|
|
984
1762
|
static of(project) {
|
|
985
|
-
const
|
|
986
|
-
return project.components.find(
|
|
1763
|
+
const isAgentConfig = (c) => c instanceof _AgentConfig;
|
|
1764
|
+
return project.components.find(isAgentConfig);
|
|
987
1765
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1766
|
+
constructor(project, options = {}) {
|
|
1767
|
+
super(project);
|
|
1768
|
+
this.options = options;
|
|
1769
|
+
}
|
|
1770
|
+
preSynthesize() {
|
|
1771
|
+
super.preSynthesize();
|
|
1772
|
+
const platforms = this.resolvePlatforms();
|
|
1773
|
+
const rules = this.resolveRules();
|
|
1774
|
+
const skills = this.resolveSkills();
|
|
1775
|
+
const subAgents = this.resolveSubAgents();
|
|
1776
|
+
const mcpServers = this.options.mcpServers ?? {};
|
|
1777
|
+
if (platforms.includes(AGENT_PLATFORM.CURSOR)) {
|
|
1778
|
+
CursorRenderer.render(
|
|
1779
|
+
this,
|
|
1780
|
+
rules,
|
|
1781
|
+
skills,
|
|
1782
|
+
subAgents,
|
|
1783
|
+
mcpServers,
|
|
1784
|
+
this.options.cursorSettings
|
|
1785
|
+
);
|
|
1786
|
+
}
|
|
1787
|
+
if (platforms.includes(AGENT_PLATFORM.CLAUDE)) {
|
|
1788
|
+
ClaudeRenderer.render(
|
|
1789
|
+
this,
|
|
1790
|
+
rules,
|
|
1791
|
+
skills,
|
|
1792
|
+
subAgents,
|
|
1793
|
+
mcpServers,
|
|
1794
|
+
this.options.claudeSettings
|
|
1795
|
+
);
|
|
1796
|
+
}
|
|
1797
|
+
if (platforms.includes(AGENT_PLATFORM.CODEX)) {
|
|
1798
|
+
CodexRenderer.render(this, rules, skills, subAgents);
|
|
1799
|
+
}
|
|
1800
|
+
if (platforms.includes(AGENT_PLATFORM.COPILOT)) {
|
|
1801
|
+
CopilotRenderer.render(this, rules, skills, subAgents);
|
|
996
1802
|
}
|
|
997
1803
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
* Value must be exactly $(...) so Projen's task runtime expands it; the shell
|
|
1001
|
-
* then expands ${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}.
|
|
1002
|
-
*/
|
|
1003
|
-
activateBranchNameEnvVar() {
|
|
1004
|
-
this.addGlobalEnvVar(
|
|
1005
|
-
"GIT_BRANCH_NAME",
|
|
1006
|
-
'$(echo "${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}")'
|
|
1007
|
-
);
|
|
1804
|
+
resolvePlatforms() {
|
|
1805
|
+
return this.options.platforms ?? [AGENT_PLATFORM.CURSOR, AGENT_PLATFORM.CLAUDE];
|
|
1008
1806
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
if (
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
if (nextDependsOn.length > 0) {
|
|
1021
|
-
turboTask.dependsOn.push(...nextDependsOn);
|
|
1807
|
+
resolveRules() {
|
|
1808
|
+
const ruleMap = /* @__PURE__ */ new Map();
|
|
1809
|
+
if (this.options.autoDetectBundles !== false) {
|
|
1810
|
+
for (const bundle of BUILT_IN_BUNDLES) {
|
|
1811
|
+
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
1812
|
+
if (bundle.name === "base" && this.options.includeBaseRules === false) {
|
|
1813
|
+
continue;
|
|
1814
|
+
}
|
|
1815
|
+
if (bundle.appliesWhen(this.project)) {
|
|
1816
|
+
for (const rule of bundle.rules) {
|
|
1817
|
+
ruleMap.set(rule.name, rule);
|
|
1022
1818
|
}
|
|
1023
|
-
nextDependsOn = [turboTask.name];
|
|
1024
|
-
} else {
|
|
1025
|
-
turboTask.isActive = false;
|
|
1026
1819
|
}
|
|
1027
|
-
}
|
|
1028
|
-
this.buildTask.dependsOn.push(...nextDependsOn);
|
|
1820
|
+
}
|
|
1029
1821
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
globalEnv: this.isRootProject && this.globalEnv.length ? this.globalEnv : void 0,
|
|
1037
|
-
globalPassThroughEnv: this.isRootProject && this.globalPassThroughEnv.length ? this.globalPassThroughEnv : void 0,
|
|
1038
|
-
ui: this.isRootProject ? this.ui : void 0,
|
|
1039
|
-
dangerouslyDisablePackageManagerCheck: this.isRootProject ? this.dangerouslyDisablePackageManagerCheck : void 0,
|
|
1040
|
-
cacheDir: this.isRootProject ? this.cacheDir : void 0,
|
|
1041
|
-
daemon: this.isRootProject ? this.daemon : void 0,
|
|
1042
|
-
envMode: this.isRootProject ? this.envMode : void 0,
|
|
1043
|
-
/**
|
|
1044
|
-
* All tasks
|
|
1045
|
-
*/
|
|
1046
|
-
tasks: this.tasks.filter((task) => task.isActive).reduce(
|
|
1047
|
-
(acc, task) => {
|
|
1048
|
-
acc[task.name] = {
|
|
1049
|
-
...task.taskConfig()
|
|
1050
|
-
};
|
|
1051
|
-
return acc;
|
|
1052
|
-
},
|
|
1053
|
-
{
|
|
1054
|
-
[this.buildTask.name]: { ...this.buildTask.taskConfig() }
|
|
1822
|
+
if (this.options.includeBundles) {
|
|
1823
|
+
for (const bundleName of this.options.includeBundles) {
|
|
1824
|
+
const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);
|
|
1825
|
+
if (bundle) {
|
|
1826
|
+
for (const rule of bundle.rules) {
|
|
1827
|
+
ruleMap.set(rule.name, rule);
|
|
1055
1828
|
}
|
|
1056
|
-
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
if (this.options.rules) {
|
|
1833
|
+
for (const rule of this.options.rules) {
|
|
1834
|
+
ruleMap.set(rule.name, rule);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
if (this.options.excludeRules) {
|
|
1838
|
+
for (const name of this.options.excludeRules) {
|
|
1839
|
+
ruleMap.delete(name);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
if (this.options.ruleExtensions) {
|
|
1843
|
+
for (const [name, extra] of Object.entries(this.options.ruleExtensions)) {
|
|
1844
|
+
const existing = ruleMap.get(name);
|
|
1845
|
+
if (existing) {
|
|
1846
|
+
ruleMap.set(name, {
|
|
1847
|
+
...existing,
|
|
1848
|
+
content: `${existing.content}
|
|
1849
|
+
|
|
1850
|
+
---
|
|
1851
|
+
|
|
1852
|
+
${extra}`
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1057
1855
|
}
|
|
1856
|
+
}
|
|
1857
|
+
return [...ruleMap.values()].sort((a, b) => {
|
|
1858
|
+
if (a.name === "project-overview") return -1;
|
|
1859
|
+
if (b.name === "project-overview") return 1;
|
|
1860
|
+
const tagA = a.tags?.[0] ?? "\uFFFF";
|
|
1861
|
+
const tagB = b.tags?.[0] ?? "\uFFFF";
|
|
1862
|
+
if (tagA !== tagB) return tagA.localeCompare(tagB);
|
|
1863
|
+
return a.name.localeCompare(b.name);
|
|
1058
1864
|
});
|
|
1059
|
-
super.preSynthesize();
|
|
1060
1865
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
},
|
|
1071
|
-
preBuildSteps: [
|
|
1072
|
-
{
|
|
1073
|
-
name: "AWS Creds for SSM",
|
|
1074
|
-
uses: "aws-actions/configure-aws-credentials@v4",
|
|
1075
|
-
with: {
|
|
1076
|
-
["role-to-assume"]: remoteCacheOptions.oidcRole,
|
|
1077
|
-
["aws-region"]: "us-east-1",
|
|
1078
|
-
["role-duration-seconds"]: "900"
|
|
1866
|
+
resolveSkills() {
|
|
1867
|
+
const skillMap = /* @__PURE__ */ new Map();
|
|
1868
|
+
if (this.options.autoDetectBundles !== false) {
|
|
1869
|
+
for (const bundle of BUILT_IN_BUNDLES) {
|
|
1870
|
+
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
1871
|
+
if (bundle.appliesWhen(this.project) && bundle.skills) {
|
|
1872
|
+
for (const skill of bundle.skills) {
|
|
1873
|
+
skillMap.set(skill.name, skill);
|
|
1874
|
+
}
|
|
1079
1875
|
}
|
|
1080
1876
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1877
|
+
}
|
|
1878
|
+
if (this.options.skills) {
|
|
1879
|
+
for (const skill of this.options.skills) {
|
|
1880
|
+
skillMap.set(skill.name, skill);
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
return [...skillMap.values()];
|
|
1884
|
+
}
|
|
1885
|
+
resolveSubAgents() {
|
|
1886
|
+
const agentMap = /* @__PURE__ */ new Map();
|
|
1887
|
+
if (this.options.autoDetectBundles !== false) {
|
|
1888
|
+
for (const bundle of BUILT_IN_BUNDLES) {
|
|
1889
|
+
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
1890
|
+
if (bundle.appliesWhen(this.project) && bundle.subAgents) {
|
|
1891
|
+
for (const agent of bundle.subAgents) {
|
|
1892
|
+
agentMap.set(agent.name, agent);
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
if (this.options.subAgents) {
|
|
1898
|
+
for (const agent of this.options.subAgents) {
|
|
1899
|
+
agentMap.set(agent.name, agent);
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
return [...agentMap.values()];
|
|
1903
|
+
}
|
|
1083
1904
|
};
|
|
1084
|
-
var TurboRepo = _TurboRepo;
|
|
1085
1905
|
|
|
1086
1906
|
// src/aws/aws-deployment-config.ts
|
|
1087
|
-
var
|
|
1907
|
+
var import_node_path = require("path");
|
|
1908
|
+
var import_utils8 = __toESM(require_lib());
|
|
1909
|
+
var import_projen8 = require("projen");
|
|
1910
|
+
var AwsDeploymentConfig = class _AwsDeploymentConfig extends import_projen8.Component {
|
|
1088
1911
|
constructor(project) {
|
|
1089
1912
|
super(project);
|
|
1090
1913
|
/**
|
|
@@ -1139,17 +1962,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends import_projen4.Comp
|
|
|
1139
1962
|
*/
|
|
1140
1963
|
get prodTargets() {
|
|
1141
1964
|
return this.awsDeploymentTargets.filter(
|
|
1142
|
-
(target) => target.awsStageType ===
|
|
1965
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD
|
|
1143
1966
|
);
|
|
1144
1967
|
}
|
|
1145
1968
|
get prodTargetsForCI() {
|
|
1146
1969
|
return this.awsDeploymentTargets.filter(
|
|
1147
|
-
(target) => target.awsStageType ===
|
|
1970
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD && target.ciDeployment
|
|
1148
1971
|
);
|
|
1149
1972
|
}
|
|
1150
1973
|
get prodTargetsForLocal() {
|
|
1151
1974
|
return this.awsDeploymentTargets.filter(
|
|
1152
|
-
(target) => target.awsStageType ===
|
|
1975
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD && target.localDeployment
|
|
1153
1976
|
);
|
|
1154
1977
|
}
|
|
1155
1978
|
/**
|
|
@@ -1158,17 +1981,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends import_projen4.Comp
|
|
|
1158
1981
|
*/
|
|
1159
1982
|
get stageTargets() {
|
|
1160
1983
|
return this.awsDeploymentTargets.filter(
|
|
1161
|
-
(target) => target.awsStageType ===
|
|
1984
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE
|
|
1162
1985
|
);
|
|
1163
1986
|
}
|
|
1164
1987
|
get stageTargetsForCI() {
|
|
1165
1988
|
return this.awsDeploymentTargets.filter(
|
|
1166
|
-
(target) => target.awsStageType ===
|
|
1989
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE && target.ciDeployment
|
|
1167
1990
|
);
|
|
1168
1991
|
}
|
|
1169
1992
|
get stageTargetsForLocal() {
|
|
1170
1993
|
return this.awsDeploymentTargets.filter(
|
|
1171
|
-
(target) => target.awsStageType ===
|
|
1994
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE && target.localDeployment
|
|
1172
1995
|
);
|
|
1173
1996
|
}
|
|
1174
1997
|
/**
|
|
@@ -1177,17 +2000,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends import_projen4.Comp
|
|
|
1177
2000
|
*/
|
|
1178
2001
|
get devTargets() {
|
|
1179
2002
|
return this.awsDeploymentTargets.filter(
|
|
1180
|
-
(target) => target.awsStageType ===
|
|
2003
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV
|
|
1181
2004
|
);
|
|
1182
2005
|
}
|
|
1183
2006
|
get devTargetsForCI() {
|
|
1184
2007
|
return this.awsDeploymentTargets.filter(
|
|
1185
|
-
(target) => target.awsStageType ===
|
|
2008
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV && target.ciDeployment
|
|
1186
2009
|
);
|
|
1187
2010
|
}
|
|
1188
2011
|
get devTargetsForLocal() {
|
|
1189
2012
|
return this.awsDeploymentTargets.filter(
|
|
1190
|
-
(target) => target.awsStageType ===
|
|
2013
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV && target.localDeployment
|
|
1191
2014
|
);
|
|
1192
2015
|
}
|
|
1193
2016
|
preSynthesize() {
|
|
@@ -1200,9 +2023,9 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends import_projen4.Comp
|
|
|
1200
2023
|
};
|
|
1201
2024
|
|
|
1202
2025
|
// src/aws/aws-deployment-target.ts
|
|
1203
|
-
var
|
|
1204
|
-
var
|
|
1205
|
-
var AwsDeploymentTarget = class _AwsDeploymentTarget extends
|
|
2026
|
+
var import_utils9 = __toESM(require_lib());
|
|
2027
|
+
var import_projen9 = require("projen");
|
|
2028
|
+
var AwsDeploymentTarget = class _AwsDeploymentTarget extends import_projen9.Component {
|
|
1206
2029
|
constructor(project, options) {
|
|
1207
2030
|
super(project);
|
|
1208
2031
|
/**
|
|
@@ -1267,11 +2090,11 @@ var AwsDeploymentTarget = class _AwsDeploymentTarget extends import_projen5.Comp
|
|
|
1267
2090
|
};
|
|
1268
2091
|
this.account = options.account;
|
|
1269
2092
|
this.region = options.region;
|
|
1270
|
-
this.awsStageType = options.awsStageType ||
|
|
1271
|
-
const role = options.deploymentTargetRole ?? options.awsEnvironmentType ??
|
|
2093
|
+
this.awsStageType = options.awsStageType || import_utils9.AWS_STAGE_TYPE.DEV;
|
|
2094
|
+
const role = options.deploymentTargetRole ?? options.awsEnvironmentType ?? import_utils9.DEPLOYMENT_TARGET_ROLE.PRIMARY;
|
|
1272
2095
|
this.deploymentTargetRole = role;
|
|
1273
2096
|
this.awsEnvironmentType = role;
|
|
1274
|
-
this.branches = options.branches ?? (this.awsStageType ===
|
|
2097
|
+
this.branches = options.branches ?? (this.awsStageType === import_utils9.AWS_STAGE_TYPE.PROD ? [
|
|
1275
2098
|
{
|
|
1276
2099
|
branch: "main"
|
|
1277
2100
|
}
|
|
@@ -1280,7 +2103,7 @@ var AwsDeploymentTarget = class _AwsDeploymentTarget extends import_projen5.Comp
|
|
|
1280
2103
|
branch: "feature/*"
|
|
1281
2104
|
}
|
|
1282
2105
|
]);
|
|
1283
|
-
this.localDeployment = options.localDeployment ?? this.awsStageType ===
|
|
2106
|
+
this.localDeployment = options.localDeployment ?? this.awsStageType === import_utils9.AWS_STAGE_TYPE.DEV;
|
|
1284
2107
|
if (this.localDeployment) {
|
|
1285
2108
|
const roleName = options.localDeploymentConfig?.roleName?.toLowerCase() || "poweruseraccess";
|
|
1286
2109
|
const profile = options.localDeploymentConfig?.profile || `${roleName}-${this.awsStageType}-${this.account}-${this.region}`;
|
|
@@ -1415,61 +2238,14 @@ var VERSION_KEYS_SKIP = [
|
|
|
1415
2238
|
// Pinned to 3.x for Vite 5 compatibility; skip until ESM-only (issue #142)
|
|
1416
2239
|
];
|
|
1417
2240
|
|
|
1418
|
-
// src/versions.ts
|
|
1419
|
-
var VERSION = {
|
|
1420
|
-
/**
|
|
1421
|
-
* CDK CLI for workflows and command line operations.
|
|
1422
|
-
*
|
|
1423
|
-
* CLI and lib are versioned separately, so this is the CLI version.
|
|
1424
|
-
*/
|
|
1425
|
-
AWS_CDK_CLI_VERSION: "2.1117.0",
|
|
1426
|
-
/**
|
|
1427
|
-
* CDK Version to use for construct projects.
|
|
1428
|
-
*
|
|
1429
|
-
* CLI and lib are versioned separately, so this is the lib version.
|
|
1430
|
-
*/
|
|
1431
|
-
AWS_CDK_LIB_VERSION: "2.248.0",
|
|
1432
|
-
/**
|
|
1433
|
-
* Version of the AWS Constructs library to use.
|
|
1434
|
-
*/
|
|
1435
|
-
AWS_CONSTRUCTS_VERSION: "10.6.0",
|
|
1436
|
-
/**
|
|
1437
|
-
* Version of Node.js to use in CI workflows at github actions.
|
|
1438
|
-
*/
|
|
1439
|
-
NODE_WORKFLOWS: "24",
|
|
1440
|
-
/**
|
|
1441
|
-
* Version of PNPM to use in workflows at github actions.
|
|
1442
|
-
*/
|
|
1443
|
-
PNPM_VERSION: "10.33.0",
|
|
1444
|
-
/**
|
|
1445
|
-
* Version of Projen to use.
|
|
1446
|
-
*/
|
|
1447
|
-
PROJEN_VERSION: "0.99.34",
|
|
1448
|
-
/**
|
|
1449
|
-
* What version of the turborepo library should we use?
|
|
1450
|
-
*/
|
|
1451
|
-
TURBO_VERSION: "2.9.4",
|
|
1452
|
-
/**
|
|
1453
|
-
* What version of Vite to use (pnpm override). Pinned to 5.x so Vitest 4.x
|
|
1454
|
-
* can load config (Vite 6+/7+ are ESM-only; see issue #142). Remove override
|
|
1455
|
-
* when moving to ESM-only test setup.
|
|
1456
|
-
*/
|
|
1457
|
-
VITE_VERSION: "5.4.11",
|
|
1458
|
-
/**
|
|
1459
|
-
* What version of Vitest to use when testRunner is 'vitest'.
|
|
1460
|
-
* Pinned to 3.x so it works with Vite 5 (Vitest 4 requires Vite 6). See issue #142.
|
|
1461
|
-
*/
|
|
1462
|
-
VITEST_VERSION: "3.2.4"
|
|
1463
|
-
};
|
|
1464
|
-
|
|
1465
2241
|
// src/jsii/jsii-faker.ts
|
|
1466
2242
|
var spec = __toESM(require("@jsii/spec"));
|
|
1467
|
-
var
|
|
2243
|
+
var import_projen10 = require("projen");
|
|
1468
2244
|
var ProjenBaseFqn = {
|
|
1469
2245
|
TYPESCRIPT_PROJECT: "projen.typescript.TypeScriptProject",
|
|
1470
2246
|
TYPESCRIPT_PROJECT_OPTIONS: "projen.typescript.TypeScriptProjectOptions"
|
|
1471
2247
|
};
|
|
1472
|
-
var JsiiFaker = class _JsiiFaker extends
|
|
2248
|
+
var JsiiFaker = class _JsiiFaker extends import_projen10.Component {
|
|
1473
2249
|
constructor(project) {
|
|
1474
2250
|
super(project);
|
|
1475
2251
|
this.project = project;
|
|
@@ -1480,7 +2256,7 @@ var JsiiFaker = class _JsiiFaker extends import_projen6.Component {
|
|
|
1480
2256
|
};
|
|
1481
2257
|
};
|
|
1482
2258
|
this._assemblyName = this.project.package.packageName;
|
|
1483
|
-
new
|
|
2259
|
+
new import_projen10.JsonFile(project, ".jsii", {
|
|
1484
2260
|
obj: () => {
|
|
1485
2261
|
return {
|
|
1486
2262
|
name: this._assemblyName,
|
|
@@ -1517,192 +2293,24 @@ var JsiiFaker = class _JsiiFaker extends import_projen6.Component {
|
|
|
1517
2293
|
}
|
|
1518
2294
|
};
|
|
1519
2295
|
|
|
1520
|
-
// src/pnpm/pnpm-workspace.ts
|
|
1521
|
-
var import_path = require("path");
|
|
1522
|
-
var import_projen7 = require("projen");
|
|
1523
|
-
var MIMIMUM_RELEASE_AGE = {
|
|
1524
|
-
ZERO_DAYS: 0,
|
|
1525
|
-
ONE_HOUR: 60,
|
|
1526
|
-
SIX_HOURS: 360,
|
|
1527
|
-
TWELVE_HOURS: 720,
|
|
1528
|
-
ONE_DAY: 1440,
|
|
1529
|
-
TWO_DAYS: 2880,
|
|
1530
|
-
THREE_DAYS: 4320,
|
|
1531
|
-
FOUR_DAYS: 5760,
|
|
1532
|
-
FIVE_DAYS: 7200,
|
|
1533
|
-
SIX_DAYS: 8640,
|
|
1534
|
-
ONE_WEEK: 10080
|
|
1535
|
-
};
|
|
1536
|
-
var PnpmWorkspace = class _PnpmWorkspace extends import_projen7.Component {
|
|
1537
|
-
/**
|
|
1538
|
-
* Get the pnpm workspace component of a project. If it does not exist,
|
|
1539
|
-
* return undefined.
|
|
1540
|
-
*
|
|
1541
|
-
* @param project
|
|
1542
|
-
* @returns
|
|
1543
|
-
*/
|
|
1544
|
-
static of(project) {
|
|
1545
|
-
const isDefined = (c) => c instanceof _PnpmWorkspace;
|
|
1546
|
-
return project.root.components.find(isDefined);
|
|
1547
|
-
}
|
|
1548
|
-
constructor(project, options = {}) {
|
|
1549
|
-
super(project);
|
|
1550
|
-
project.tryFindObjectFile("package.json")?.addDeletionOverride("pnpm");
|
|
1551
|
-
this.fileName = options.fileName ?? "pnpm-workspace.yaml";
|
|
1552
|
-
this.minimumReleaseAge = options.minimumReleaseAge ?? MIMIMUM_RELEASE_AGE.ONE_DAY;
|
|
1553
|
-
this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude ? ["@codedrifters/*", ...options.minimumReleaseAgeExclude] : ["@codedrifters/*"];
|
|
1554
|
-
this.onlyBuiltDependencies = options.onlyBuiltDependencies ? options.onlyBuiltDependencies : [];
|
|
1555
|
-
this.ignoredBuiltDependencies = options.ignoredBuiltDependencies ? options.ignoredBuiltDependencies : [];
|
|
1556
|
-
this.subprojects = options.subprojects ?? [];
|
|
1557
|
-
this.defaultCatalog = options.defaultCatalog;
|
|
1558
|
-
this.namedCatalogs = options.namedCatalogs;
|
|
1559
|
-
project.addPackageIgnore(this.fileName);
|
|
1560
|
-
new import_projen7.YamlFile(this.project, this.fileName, {
|
|
1561
|
-
obj: () => {
|
|
1562
|
-
const pnpmConfig = {};
|
|
1563
|
-
const packages = new Array();
|
|
1564
|
-
for (const subproject of project.subprojects) {
|
|
1565
|
-
packages.push((0, import_path.relative)(this.project.outdir, subproject.outdir));
|
|
1566
|
-
}
|
|
1567
|
-
const packageSet = new Set(packages);
|
|
1568
|
-
for (const subprojectPath of this.subprojects) {
|
|
1569
|
-
packageSet.add(subprojectPath);
|
|
1570
|
-
}
|
|
1571
|
-
if (this.subprojects.length > 0) {
|
|
1572
|
-
packages.length = 0;
|
|
1573
|
-
packages.push(...packageSet);
|
|
1574
|
-
}
|
|
1575
|
-
pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;
|
|
1576
|
-
if (this.minimumReleaseAgeExclude.length > 0) {
|
|
1577
|
-
pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;
|
|
1578
|
-
}
|
|
1579
|
-
if (this.onlyBuiltDependencies.length > 0) {
|
|
1580
|
-
pnpmConfig.onlyBuiltDependencies = this.onlyBuiltDependencies;
|
|
1581
|
-
}
|
|
1582
|
-
if (this.ignoredBuiltDependencies.length > 0) {
|
|
1583
|
-
pnpmConfig.ignoreBuiltDependencies = this.ignoredBuiltDependencies;
|
|
1584
|
-
}
|
|
1585
|
-
if (this.defaultCatalog && Object.keys(this.defaultCatalog).length > 0) {
|
|
1586
|
-
pnpmConfig.catalog = this.defaultCatalog;
|
|
1587
|
-
}
|
|
1588
|
-
if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {
|
|
1589
|
-
pnpmConfig.namedCatalogs = this.namedCatalogs;
|
|
1590
|
-
}
|
|
1591
|
-
return {
|
|
1592
|
-
...packages.length > 0 ? { packages } : {},
|
|
1593
|
-
...pnpmConfig ? { ...pnpmConfig } : {}
|
|
1594
|
-
};
|
|
1595
|
-
}
|
|
1596
|
-
});
|
|
1597
|
-
}
|
|
1598
|
-
};
|
|
1599
|
-
|
|
1600
2296
|
// src/projects/monorepo-project.ts
|
|
1601
2297
|
var import_javascript3 = require("projen/lib/javascript");
|
|
1602
|
-
var
|
|
2298
|
+
var import_typescript3 = require("projen/lib/typescript");
|
|
1603
2299
|
var import_ts_deepmerge2 = require("ts-deepmerge");
|
|
1604
2300
|
|
|
1605
2301
|
// src/tasks/reset-task.ts
|
|
1606
|
-
var
|
|
2302
|
+
var import_projen12 = require("projen");
|
|
1607
2303
|
|
|
1608
2304
|
// src/projects/typescript-project.ts
|
|
1609
|
-
var
|
|
2305
|
+
var import_projen11 = require("projen");
|
|
1610
2306
|
var import_javascript2 = require("projen/lib/javascript");
|
|
1611
2307
|
var import_release = require("projen/lib/release");
|
|
1612
2308
|
var import_ts_deepmerge = require("ts-deepmerge");
|
|
1613
|
-
|
|
1614
|
-
// src/vitest/vitest-component.ts
|
|
1615
|
-
var import_projen8 = require("projen");
|
|
1616
|
-
var import_javascript = require("projen/lib/javascript");
|
|
1617
|
-
var import_textfile3 = require("projen/lib/textfile");
|
|
1618
|
-
var Vitest = class _Vitest extends import_projen8.Component {
|
|
1619
|
-
constructor(project, options = {}) {
|
|
1620
|
-
super(project);
|
|
1621
|
-
this.project = project;
|
|
1622
|
-
this.configFilePath = options.configFilePath ?? "vitest.config.ts";
|
|
1623
|
-
const config = options.config ?? {};
|
|
1624
|
-
this.include = config.include ?? ["**/*.{test,spec}.?(c|m)[jt]s?(x)"];
|
|
1625
|
-
this.exclude = config.exclude ?? [
|
|
1626
|
-
"**/node_modules/**",
|
|
1627
|
-
"**/dist/**",
|
|
1628
|
-
"**/lib/**",
|
|
1629
|
-
"**/.?*"
|
|
1630
|
-
];
|
|
1631
|
-
this.environment = config.environment ?? "node";
|
|
1632
|
-
this.passWithNoTests = config.passWithNoTests ?? true;
|
|
1633
|
-
this.coverageEnabled = config.coverageEnabled ?? true;
|
|
1634
|
-
this.coverageDirectory = config.coverageDirectory ?? "coverage";
|
|
1635
|
-
this.coverageReporters = config.coverageReporters ?? ["text", "lcov"];
|
|
1636
|
-
this.version = options.vitestVersion ?? VERSION.VITEST_VERSION;
|
|
1637
|
-
project.addDevDeps(`vitest@${this.version}`);
|
|
1638
|
-
if (this.coverageEnabled) {
|
|
1639
|
-
project.addDevDeps(`@vitest/coverage-v8@${this.version}`);
|
|
1640
|
-
}
|
|
1641
|
-
const coveragePath = `/${this.coverageDirectory}/`;
|
|
1642
|
-
project.gitignore.addPatterns(coveragePath);
|
|
1643
|
-
project.npmignore?.exclude(coveragePath);
|
|
1644
|
-
this.addTestTasks();
|
|
1645
|
-
this.synthesizeConfig();
|
|
1646
|
-
}
|
|
1647
|
-
/**
|
|
1648
|
-
* Find the Vitest component on a project.
|
|
1649
|
-
*/
|
|
1650
|
-
static of(project) {
|
|
1651
|
-
const isVitest = (c) => c instanceof _Vitest;
|
|
1652
|
-
return project.components.find(isVitest);
|
|
1653
|
-
}
|
|
1654
|
-
preSynthesize() {
|
|
1655
|
-
super.preSynthesize();
|
|
1656
|
-
for (const component of this.project.components) {
|
|
1657
|
-
if (component instanceof import_javascript.Jest) {
|
|
1658
|
-
throw new Error("Vitest cannot be used together with Jest");
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
}
|
|
1662
|
-
addTestTasks() {
|
|
1663
|
-
this.project.testTask.exec("vitest run --update");
|
|
1664
|
-
if (!this.project.tasks.tryFind("test:watch")) {
|
|
1665
|
-
this.project.addTask("test:watch", {
|
|
1666
|
-
description: "Run tests in watch mode",
|
|
1667
|
-
exec: "vitest watch",
|
|
1668
|
-
receiveArgs: true
|
|
1669
|
-
});
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
synthesizeConfig() {
|
|
1673
|
-
this.project.tryRemoveFile(this.configFilePath);
|
|
1674
|
-
new import_textfile3.TextFile(this, this.configFilePath, {
|
|
1675
|
-
lines: this.renderConfig()
|
|
1676
|
-
});
|
|
1677
|
-
}
|
|
1678
|
-
renderConfig() {
|
|
1679
|
-
return [
|
|
1680
|
-
'import { defineConfig } from "vitest/config";',
|
|
1681
|
-
"",
|
|
1682
|
-
"export default defineConfig({",
|
|
1683
|
-
" test: {",
|
|
1684
|
-
` include: ${JSON.stringify(this.include)},`,
|
|
1685
|
-
` exclude: ${JSON.stringify(this.exclude)},`,
|
|
1686
|
-
` environment: "${this.environment}",`,
|
|
1687
|
-
` passWithNoTests: ${this.passWithNoTests},`,
|
|
1688
|
-
" coverage: {",
|
|
1689
|
-
` enabled: ${this.coverageEnabled},`,
|
|
1690
|
-
` provider: "v8",`,
|
|
1691
|
-
` reportsDirectory: "${this.coverageDirectory}",`,
|
|
1692
|
-
` reporter: ${JSON.stringify(this.coverageReporters)},`,
|
|
1693
|
-
" },",
|
|
1694
|
-
" },",
|
|
1695
|
-
"});"
|
|
1696
|
-
];
|
|
1697
|
-
}
|
|
1698
|
-
};
|
|
1699
|
-
|
|
1700
|
-
// src/projects/typescript-project.ts
|
|
1701
2309
|
var TestRunner = {
|
|
1702
2310
|
JEST: "jest",
|
|
1703
2311
|
VITEST: "vitest"
|
|
1704
2312
|
};
|
|
1705
|
-
var TypeScriptProject = class extends
|
|
2313
|
+
var TypeScriptProject = class extends import_projen11.typescript.TypeScriptProject {
|
|
1706
2314
|
constructor(userOptions) {
|
|
1707
2315
|
const pnpmVersion = userOptions.parent && userOptions.parent instanceof MonorepoProject ? userOptions.parent.pnpmVersion : VERSION.PNPM_VERSION;
|
|
1708
2316
|
const pnpmWorkspace = userOptions.parent && userOptions.parent instanceof MonorepoProject ? PnpmWorkspace.of(userOptions.parent) : void 0;
|
|
@@ -1862,7 +2470,7 @@ var TypeScriptProject = class extends import_projen9.typescript.TypeScriptProjec
|
|
|
1862
2470
|
};
|
|
1863
2471
|
|
|
1864
2472
|
// src/tasks/reset-task.ts
|
|
1865
|
-
var ResetTask = class _ResetTask extends
|
|
2473
|
+
var ResetTask = class _ResetTask extends import_projen12.Component {
|
|
1866
2474
|
constructor(project, options = {}) {
|
|
1867
2475
|
super(project);
|
|
1868
2476
|
this.project = project;
|
|
@@ -1935,12 +2543,12 @@ var ResetTask = class _ResetTask extends import_projen10.Component {
|
|
|
1935
2543
|
};
|
|
1936
2544
|
|
|
1937
2545
|
// src/vscode/vscode.ts
|
|
1938
|
-
var
|
|
1939
|
-
var VSCodeConfig = class extends
|
|
2546
|
+
var import_projen13 = require("projen");
|
|
2547
|
+
var VSCodeConfig = class extends import_projen13.Component {
|
|
1940
2548
|
constructor(project) {
|
|
1941
2549
|
super(project);
|
|
1942
|
-
const vsConfig = new
|
|
1943
|
-
const vsSettings = new
|
|
2550
|
+
const vsConfig = new import_projen13.vscode.VsCode(project);
|
|
2551
|
+
const vsSettings = new import_projen13.vscode.VsCodeSettings(vsConfig);
|
|
1944
2552
|
vsSettings.addSetting("editor.tabSize", 2);
|
|
1945
2553
|
vsSettings.addSetting("editor.detectIndentation", false);
|
|
1946
2554
|
vsSettings.addSetting("editor.bracketPairColorization.enabled", true);
|
|
@@ -2084,7 +2692,7 @@ function addBuildCompleteJob(buildWorkflow) {
|
|
|
2084
2692
|
// src/projects/monorepo-project.ts
|
|
2085
2693
|
var CONFIGULATOR_PACKAGE_NAME = "@codedrifters/configulator";
|
|
2086
2694
|
var postInstallDependenciesMap = /* @__PURE__ */ new WeakMap();
|
|
2087
|
-
var MonorepoProject = class extends
|
|
2695
|
+
var MonorepoProject = class extends import_typescript3.TypeScriptAppProject {
|
|
2088
2696
|
constructor(userOptions) {
|
|
2089
2697
|
const buildWorkflowOptions = userOptions.turboOptions?.remoteCacheOptions ? TurboRepo.buildWorkflowOptions(
|
|
2090
2698
|
userOptions.turboOptions.remoteCacheOptions
|
|
@@ -2312,6 +2920,9 @@ var MonorepoProject = class extends import_typescript.TypeScriptAppProject {
|
|
|
2312
2920
|
if (options.approveMergeUpgradeOptions) {
|
|
2313
2921
|
addApproveMergeUpgradeWorkflow(this, options.approveMergeUpgradeOptions);
|
|
2314
2922
|
}
|
|
2923
|
+
if (options.agentConfig) {
|
|
2924
|
+
new AgentConfig(this, options.agentConfigOptions);
|
|
2925
|
+
}
|
|
2315
2926
|
if (this.buildWorkflow) {
|
|
2316
2927
|
addBuildCompleteJob(this.buildWorkflow);
|
|
2317
2928
|
}
|
|
@@ -2370,9 +2981,9 @@ var MonorepoProject = class extends import_typescript.TypeScriptAppProject {
|
|
|
2370
2981
|
|
|
2371
2982
|
// src/typescript/typescript-config.ts
|
|
2372
2983
|
var import_node_path2 = require("path");
|
|
2373
|
-
var
|
|
2984
|
+
var import_projen14 = require("projen");
|
|
2374
2985
|
var import_path2 = require("projen/lib/util/path");
|
|
2375
|
-
var TypeScriptConfig = class extends
|
|
2986
|
+
var TypeScriptConfig = class extends import_projen14.Component {
|
|
2376
2987
|
constructor(project) {
|
|
2377
2988
|
super(project);
|
|
2378
2989
|
let tsPaths = {};
|
|
@@ -2399,13 +3010,13 @@ var TypeScriptConfig = class extends import_projen12.Component {
|
|
|
2399
3010
|
};
|
|
2400
3011
|
|
|
2401
3012
|
// src/workflows/aws-deploy-workflow.ts
|
|
2402
|
-
var
|
|
2403
|
-
var
|
|
3013
|
+
var import_utils10 = __toESM(require_lib());
|
|
3014
|
+
var import_projen15 = require("projen");
|
|
2404
3015
|
var import_build = require("projen/lib/build");
|
|
2405
3016
|
var import_github = require("projen/lib/github");
|
|
2406
3017
|
var import_workflows_model4 = require("projen/lib/github/workflows-model");
|
|
2407
3018
|
var PROD_DEPLOY_NAME = "prod-deploy";
|
|
2408
|
-
var AwsDeployWorkflow = class _AwsDeployWorkflow extends
|
|
3019
|
+
var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen15.Component {
|
|
2409
3020
|
constructor(project, options = {}) {
|
|
2410
3021
|
super(project);
|
|
2411
3022
|
this.project = project;
|
|
@@ -2416,7 +3027,7 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen13.Compone
|
|
|
2416
3027
|
* @deprecated Use deployment target role terminology elsewhere. This property is maintained for backward compatibility.
|
|
2417
3028
|
* @default 'primary' (this is the only type supported currently)
|
|
2418
3029
|
*/
|
|
2419
|
-
this.awsEnvironmentType =
|
|
3030
|
+
this.awsEnvironmentType = import_utils10.DEPLOYMENT_TARGET_ROLE.PRIMARY;
|
|
2420
3031
|
this.setupNode = () => {
|
|
2421
3032
|
return [
|
|
2422
3033
|
{
|
|
@@ -2526,7 +3137,7 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen13.Compone
|
|
|
2526
3137
|
}
|
|
2527
3138
|
const turbo = TurboRepo.of(this.rootProject);
|
|
2528
3139
|
const buildWorkflowOptions = turbo?.remoteCacheOptions ? TurboRepo.buildWorkflowOptions(turbo.remoteCacheOptions) : {};
|
|
2529
|
-
this.awsStageType = options.awsStageType ??
|
|
3140
|
+
this.awsStageType = options.awsStageType ?? import_utils10.AWS_STAGE_TYPE.DEV;
|
|
2530
3141
|
this.awsDeploymentTargets = options.awsDeploymentTargets ?? AwsDeploymentConfig.of(project)?.awsDeploymentTargets.filter(
|
|
2531
3142
|
(target) => target.awsStageType === this.awsStageType && target.ciDeployment
|
|
2532
3143
|
) ?? [];
|
|
@@ -2702,6 +3313,14 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen13.Compone
|
|
|
2702
3313
|
Vitest,
|
|
2703
3314
|
addApproveMergeUpgradeWorkflow,
|
|
2704
3315
|
addBuildCompleteJob,
|
|
2705
|
-
|
|
3316
|
+
awsCdkBundle,
|
|
3317
|
+
baseBundle,
|
|
3318
|
+
getLatestEligibleVersion,
|
|
3319
|
+
jestBundle,
|
|
3320
|
+
pnpmBundle,
|
|
3321
|
+
projenBundle,
|
|
3322
|
+
turborepoBundle,
|
|
3323
|
+
typescriptBundle,
|
|
3324
|
+
vitestBundle
|
|
2706
3325
|
});
|
|
2707
3326
|
//# sourceMappingURL=index.js.map
|