@codedrifters/configulator 0.0.153 → 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.js CHANGED
@@ -175,11 +175,18 @@ var require_lib = __commonJS({
175
175
  // src/index.ts
176
176
  var index_exports = {};
177
177
  __export(index_exports, {
178
+ AGENT_MODEL: () => AGENT_MODEL,
179
+ AGENT_PLATFORM: () => AGENT_PLATFORM,
180
+ AGENT_RULE_SCOPE: () => AGENT_RULE_SCOPE,
181
+ AgentConfig: () => AgentConfig,
178
182
  AwsDeployWorkflow: () => AwsDeployWorkflow,
179
183
  AwsDeploymentConfig: () => AwsDeploymentConfig,
180
184
  AwsDeploymentTarget: () => AwsDeploymentTarget,
185
+ BUILT_IN_BUNDLES: () => BUILT_IN_BUNDLES,
186
+ CLAUDE_RULE_TARGET: () => CLAUDE_RULE_TARGET,
181
187
  COMPLETE_JOB_ID: () => COMPLETE_JOB_ID,
182
188
  JsiiFaker: () => JsiiFaker,
189
+ MCP_TRANSPORT: () => MCP_TRANSPORT,
183
190
  MERGE_METHODS: () => MERGE_METHODS,
184
191
  MIMIMUM_RELEASE_AGE: () => MIMIMUM_RELEASE_AGE,
185
192
  MonorepoProject: () => MonorepoProject,
@@ -200,14 +207,556 @@ __export(index_exports, {
200
207
  Vitest: () => Vitest,
201
208
  addApproveMergeUpgradeWorkflow: () => addApproveMergeUpgradeWorkflow,
202
209
  addBuildCompleteJob: () => addBuildCompleteJob,
203
- getLatestEligibleVersion: () => getLatestEligibleVersion
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
204
219
  });
205
220
  module.exports = __toCommonJS(index_exports);
206
221
 
207
- // src/aws/aws-deployment-config.ts
208
- var import_node_path = require("path");
209
- var import_utils = __toESM(require_lib());
222
+ // src/agent/agent-config.ts
223
+ var import_projen7 = require("projen");
224
+
225
+ // src/agent/types.ts
226
+ var AGENT_RULE_SCOPE = {
227
+ ALWAYS: "always",
228
+ FILE_PATTERN: "file-pattern"
229
+ };
230
+ var AGENT_PLATFORM = {
231
+ CURSOR: "cursor",
232
+ CLAUDE: "claude",
233
+ CODEX: "codex",
234
+ COPILOT: "copilot"
235
+ };
236
+ var CLAUDE_RULE_TARGET = {
237
+ SCOPED_FILE: "scoped-file",
238
+ AGENTS_MD: "agents-md",
239
+ CLAUDE_MD: "claude-md"
240
+ };
241
+ var AGENT_MODEL = {
242
+ INHERIT: "inherit",
243
+ FAST: "fast",
244
+ BALANCED: "balanced",
245
+ POWERFUL: "powerful"
246
+ };
247
+ var MCP_TRANSPORT = {
248
+ STDIO: "stdio",
249
+ HTTP: "http",
250
+ SSE: "sse"
251
+ };
252
+
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");
210
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 {
589
+ /**
590
+ * Get the pnpm workspace component of a project. If it does not exist,
591
+ * return undefined.
592
+ *
593
+ * @param project
594
+ * @returns
595
+ */
596
+ static of(project) {
597
+ const isDefined = (c) => c instanceof _PnpmWorkspace;
598
+ return project.root.components.find(isDefined);
599
+ }
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));
618
+ }
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
+ };
647
+ }
648
+ });
649
+ }
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");
211
760
 
212
761
  // src/turbo/turbo-repo-task.ts
213
762
  var import_lib = require("projen/lib");
@@ -250,8 +799,6 @@ var TurboRepoTask = class extends import_lib.Component {
250
799
  };
251
800
 
252
801
  // src/turbo/turbo-repo.ts
253
- var import_lib2 = require("projen/lib");
254
- var import_workflows_model = require("projen/lib/github/workflows-model");
255
802
  var ROOT_TURBO_TASK_NAME = "turbo:build";
256
803
  var ROOT_CI_TASK_NAME = "build:all";
257
804
  var _TurboRepo = class _TurboRepo extends import_lib2.Component {
@@ -428,38 +975,939 @@ var _TurboRepo = class _TurboRepo extends import_lib2.Component {
428
975
  {
429
976
  [this.buildTask.name]: { ...this.buildTask.taskConfig() }
430
977
  }
431
- )
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;
1389
+ }
1390
+ }
1391
+ if (Object.keys(hooks).length > 0) {
1392
+ obj.hooks = hooks;
1393
+ hasContent = true;
1394
+ }
1395
+ }
1396
+ const allMcpServers = {};
1397
+ for (const [name, config] of Object.entries(mcpServers)) {
1398
+ const server = {};
1399
+ if (config.command) server.command = config.command;
1400
+ if (config.args) server.args = [...config.args];
1401
+ if (config.url) server.url = config.url;
1402
+ if (config.env) server.env = { ...config.env };
1403
+ allMcpServers[name] = server;
1404
+ }
1405
+ if (settings?.mcpServers) {
1406
+ for (const [name, config] of Object.entries(settings.mcpServers)) {
1407
+ const server = {};
1408
+ if (config.command) server.command = config.command;
1409
+ if (config.args) server.args = [...config.args];
1410
+ if (config.url) server.url = config.url;
1411
+ if (config.env) server.env = { ...config.env };
1412
+ allMcpServers[name] = server;
1413
+ }
1414
+ }
1415
+ if (Object.keys(allMcpServers).length > 0) {
1416
+ obj.mcpServers = allMcpServers;
1417
+ hasContent = true;
1418
+ }
1419
+ if (settings?.allowedMcpServers?.length) {
1420
+ obj.allowedMcpServers = [...settings.allowedMcpServers];
1421
+ hasContent = true;
1422
+ }
1423
+ if (settings?.env && Object.keys(settings.env).length > 0) {
1424
+ obj.env = { ...settings.env };
1425
+ hasContent = true;
1426
+ }
1427
+ if (settings?.sandbox) {
1428
+ obj.sandbox = _ClaudeRenderer.buildSandboxObj(settings.sandbox);
1429
+ hasContent = true;
1430
+ }
1431
+ if (settings?.autoMode) {
1432
+ const autoMode = {};
1433
+ if (settings.autoMode.environment?.length) {
1434
+ autoMode.environment = [...settings.autoMode.environment];
1435
+ }
1436
+ if (settings.autoMode.allow?.length) {
1437
+ autoMode.allow = [...settings.autoMode.allow];
1438
+ }
1439
+ if (settings.autoMode.soft_deny?.length) {
1440
+ autoMode.soft_deny = [...settings.autoMode.soft_deny];
1441
+ }
1442
+ if (Object.keys(autoMode).length > 0) {
1443
+ obj.autoMode = autoMode;
1444
+ hasContent = true;
1445
+ }
1446
+ }
1447
+ if (settings?.disableBypassPermissionsMode) {
1448
+ obj.disableBypassPermissionsMode = settings.disableBypassPermissionsMode;
1449
+ hasContent = true;
1450
+ }
1451
+ if (settings?.disableAutoMode) {
1452
+ obj.disableAutoMode = settings.disableAutoMode;
1453
+ hasContent = true;
1454
+ }
1455
+ if (settings?.disableAllHooks !== void 0) {
1456
+ obj.disableAllHooks = settings.disableAllHooks;
1457
+ hasContent = true;
1458
+ }
1459
+ if (settings?.excludeSensitivePatterns?.length) {
1460
+ obj.excludeSensitivePatterns = [...settings.excludeSensitivePatterns];
1461
+ hasContent = true;
1462
+ }
1463
+ if (settings?.attribution) {
1464
+ obj.attribution = settings.attribution;
1465
+ hasContent = true;
1466
+ }
1467
+ if (!hasContent) return;
1468
+ new import_projen5.JsonFile(component, ".claude/settings.json", { obj });
1469
+ }
1470
+ static buildSandboxObj(sandbox) {
1471
+ const obj = {};
1472
+ if (sandbox.enabled !== void 0) obj.enabled = sandbox.enabled;
1473
+ if (sandbox.mode) obj.mode = sandbox.mode;
1474
+ if (sandbox.failIfUnavailable !== void 0) {
1475
+ obj.failIfUnavailable = sandbox.failIfUnavailable;
1476
+ }
1477
+ if (sandbox.autoAllowBashIfSandboxed !== void 0) {
1478
+ obj.autoAllowBashIfSandboxed = sandbox.autoAllowBashIfSandboxed;
1479
+ }
1480
+ if (sandbox.excludedCommands?.length) {
1481
+ obj.excludedCommands = [...sandbox.excludedCommands];
1482
+ }
1483
+ if (sandbox.filesystem) {
1484
+ const fs = {};
1485
+ if (sandbox.filesystem.allowRead?.length) {
1486
+ fs.allowRead = [...sandbox.filesystem.allowRead];
1487
+ }
1488
+ if (sandbox.filesystem.denyRead?.length) {
1489
+ fs.denyRead = [...sandbox.filesystem.denyRead];
1490
+ }
1491
+ if (sandbox.filesystem.allowWrite?.length) {
1492
+ fs.allowWrite = [...sandbox.filesystem.allowWrite];
1493
+ }
1494
+ if (sandbox.filesystem.denyWrite?.length) {
1495
+ fs.denyWrite = [...sandbox.filesystem.denyWrite];
1496
+ }
1497
+ if (Object.keys(fs).length > 0) obj.filesystem = fs;
1498
+ }
1499
+ if (sandbox.network) {
1500
+ const net = {};
1501
+ if (sandbox.network.allowedDomains?.length) {
1502
+ net.allowedDomains = [...sandbox.network.allowedDomains];
1503
+ }
1504
+ if (sandbox.network.denyDomains?.length) {
1505
+ net.denyDomains = [...sandbox.network.denyDomains];
1506
+ }
1507
+ if (Object.keys(net).length > 0) obj.network = net;
1508
+ }
1509
+ return obj;
1510
+ }
1511
+ static renderSkills(component, skills) {
1512
+ for (const skill of skills) {
1513
+ const lines = [];
1514
+ lines.push("---");
1515
+ lines.push(`name: "${skill.name}"`);
1516
+ lines.push(`description: "${skill.description}"`);
1517
+ if (skill.disableModelInvocation) {
1518
+ lines.push(`disable-model-invocation: true`);
1519
+ }
1520
+ if (skill.userInvocable === false) {
1521
+ lines.push(`user-invocable: false`);
1522
+ }
1523
+ if (skill.model) {
1524
+ lines.push(`model: "${skill.model}"`);
1525
+ }
1526
+ if (skill.effort) {
1527
+ lines.push(`effort: "${skill.effort}"`);
1528
+ }
1529
+ if (skill.paths && skill.paths.length > 0) {
1530
+ lines.push(`paths:`);
1531
+ for (const p of skill.paths) {
1532
+ lines.push(` - "${p}"`);
1533
+ }
1534
+ }
1535
+ if (skill.allowedTools && skill.allowedTools.length > 0) {
1536
+ lines.push(`allowed-tools:`);
1537
+ for (const tool of skill.allowedTools) {
1538
+ lines.push(` - "${tool}"`);
1539
+ }
1540
+ }
1541
+ lines.push("---");
1542
+ lines.push("");
1543
+ lines.push(...skill.instructions.split("\n"));
1544
+ new import_textfile2.TextFile(component, `.claude/skills/${skill.name}/SKILL.md`, {
1545
+ lines
1546
+ });
1547
+ }
1548
+ }
1549
+ static renderSubAgents(component, subAgents) {
1550
+ for (const agent of subAgents) {
1551
+ if (agent.platforms?.claude?.exclude) continue;
1552
+ const lines = [];
1553
+ lines.push("---");
1554
+ lines.push(`name: ${agent.name}`);
1555
+ lines.push(`description: >-`);
1556
+ lines.push(` ${agent.description}`);
1557
+ if (agent.model) {
1558
+ lines.push(`model: ${agent.model}`);
1559
+ }
1560
+ if (agent.tools && agent.tools.length > 0) {
1561
+ lines.push(`tools:`);
1562
+ for (const tool of agent.tools) {
1563
+ lines.push(` - "${tool}"`);
1564
+ }
1565
+ }
1566
+ if (agent.maxTurns) {
1567
+ lines.push(`max_turns: ${agent.maxTurns}`);
1568
+ }
1569
+ if (agent.platforms?.claude?.permissionMode) {
1570
+ lines.push(`permission_mode: ${agent.platforms.claude.permissionMode}`);
1571
+ }
1572
+ if (agent.platforms?.claude?.isolation) {
1573
+ lines.push(`isolation: ${agent.platforms.claude.isolation}`);
1574
+ }
1575
+ if (agent.platforms?.claude?.effort) {
1576
+ lines.push(`effort: ${agent.platforms.claude.effort}`);
1577
+ }
1578
+ lines.push("---");
1579
+ lines.push("");
1580
+ lines.push(...agent.prompt.split("\n"));
1581
+ new import_textfile2.TextFile(component, `.claude/agents/${agent.name}.md`, { lines });
1582
+ }
1583
+ }
1584
+ /**
1585
+ * Determine the default Claude rule target based on rule scope.
1586
+ * ALWAYS-scoped rules default to CLAUDE_MD; FILE_PATTERN rules default to SCOPED_FILE.
1587
+ */
1588
+ static defaultTarget(rule) {
1589
+ return rule.scope === AGENT_RULE_SCOPE.ALWAYS ? CLAUDE_RULE_TARGET.CLAUDE_MD : CLAUDE_RULE_TARGET.SCOPED_FILE;
1590
+ }
1591
+ };
1592
+
1593
+ // src/agent/renderers/codex-renderer.ts
1594
+ var CodexRenderer = class {
1595
+ static render(_component, _rules, _skills, _subAgents) {
1596
+ }
1597
+ };
1598
+
1599
+ // src/agent/renderers/copilot-renderer.ts
1600
+ var CopilotRenderer = class {
1601
+ static render(_component, _rules, _skills, _subAgents) {
1602
+ }
1603
+ };
1604
+
1605
+ // src/agent/renderers/cursor-renderer.ts
1606
+ var import_projen6 = require("projen");
1607
+ var import_textfile3 = require("projen/lib/textfile");
1608
+ var GENERATED_MARKER2 = "# ~~ Generated by @codedrifters/configulator. Edits welcome \u2014 please contribute improvements back. ~~";
1609
+ var CursorRenderer = class _CursorRenderer {
1610
+ /**
1611
+ * Render all Cursor configuration files.
1612
+ */
1613
+ static render(component, rules, skills, subAgents, mcpServers, settings) {
1614
+ _CursorRenderer.renderRules(component, rules);
1615
+ _CursorRenderer.renderSkills(component, skills);
1616
+ _CursorRenderer.renderSubAgents(component, subAgents);
1617
+ _CursorRenderer.renderMcpServers(component, mcpServers);
1618
+ _CursorRenderer.renderHooks(component, settings);
1619
+ _CursorRenderer.renderIgnoreFiles(component, settings);
1620
+ }
1621
+ static renderRules(component, rules) {
1622
+ for (const rule of rules) {
1623
+ if (rule.platforms?.cursor?.exclude) continue;
1624
+ const lines = [];
1625
+ const description = rule.platforms?.cursor?.description ?? rule.description;
1626
+ const isAlways = rule.scope === AGENT_RULE_SCOPE.ALWAYS;
1627
+ lines.push("---");
1628
+ lines.push(`description: "${description}"`);
1629
+ lines.push(`alwaysApply: ${isAlways}`);
1630
+ if (!isAlways && rule.filePatterns && rule.filePatterns.length > 0) {
1631
+ lines.push(`path: ${JSON.stringify([...rule.filePatterns])}`);
1632
+ }
1633
+ lines.push("---");
1634
+ lines.push("");
1635
+ lines.push(...rule.content.split("\n"));
1636
+ new import_textfile3.TextFile(component, `.cursor/rules/${rule.name}.mdc`, { lines });
1637
+ }
1638
+ }
1639
+ static renderSkills(component, skills) {
1640
+ for (const skill of skills) {
1641
+ const lines = [];
1642
+ lines.push("---");
1643
+ lines.push(`name: "${skill.name}"`);
1644
+ lines.push(`description: "${skill.description}"`);
1645
+ if (skill.disableModelInvocation) {
1646
+ lines.push(`disable-model-invocation: true`);
1647
+ }
1648
+ if (skill.userInvocable === false) {
1649
+ lines.push(`user-invocable: false`);
1650
+ }
1651
+ if (skill.allowedTools && skill.allowedTools.length > 0) {
1652
+ lines.push(`allowed-tools:`);
1653
+ for (const tool of skill.allowedTools) {
1654
+ lines.push(` - "${tool}"`);
1655
+ }
1656
+ }
1657
+ lines.push("---");
1658
+ lines.push("");
1659
+ lines.push(...skill.instructions.split("\n"));
1660
+ new import_textfile3.TextFile(component, `.cursor/skills/${skill.name}/SKILL.md`, {
1661
+ lines
1662
+ });
1663
+ }
1664
+ }
1665
+ static renderSubAgents(component, subAgents) {
1666
+ for (const agent of subAgents) {
1667
+ if (agent.platforms?.cursor?.exclude) continue;
1668
+ const lines = [];
1669
+ lines.push("---");
1670
+ lines.push(`name: ${agent.name}`);
1671
+ lines.push(`description: >-`);
1672
+ lines.push(` ${agent.description}`);
1673
+ if (agent.model) {
1674
+ lines.push(`model: ${agent.model}`);
1675
+ }
1676
+ if (agent.platforms?.cursor?.readonly) {
1677
+ lines.push(`readonly: true`);
1678
+ }
1679
+ if (agent.platforms?.cursor?.isBackground) {
1680
+ lines.push(`is_background: true`);
1681
+ }
1682
+ lines.push("---");
1683
+ lines.push("");
1684
+ lines.push(...agent.prompt.split("\n"));
1685
+ new import_textfile3.TextFile(component, `.cursor/agents/${agent.name}.md`, { lines });
1686
+ }
1687
+ }
1688
+ static renderMcpServers(component, mcpServers) {
1689
+ const serverNames = Object.keys(mcpServers);
1690
+ if (serverNames.length === 0) return;
1691
+ const obj = { mcpServers: {} };
1692
+ const servers = obj.mcpServers;
1693
+ for (const [name, config] of Object.entries(mcpServers)) {
1694
+ const server = {};
1695
+ if (config.command) server.command = config.command;
1696
+ if (config.args) server.args = [...config.args];
1697
+ if (config.url) server.url = config.url;
1698
+ if (config.env) server.env = { ...config.env };
1699
+ servers[name] = server;
1700
+ }
1701
+ new import_projen6.JsonFile(component, ".cursor/mcp.json", { obj });
1702
+ }
1703
+ static renderHooks(component, settings) {
1704
+ if (!settings?.hooks) return;
1705
+ const hooks = {};
1706
+ const {
1707
+ beforeSubmitPrompt,
1708
+ beforeShellExecution,
1709
+ beforeMCPExecution,
1710
+ beforeReadFile,
1711
+ afterFileEdit,
1712
+ stop
1713
+ } = settings.hooks;
1714
+ if (beforeSubmitPrompt?.length) {
1715
+ hooks.beforeSubmitPrompt = beforeSubmitPrompt.map((h) => ({
1716
+ command: h.command
1717
+ }));
1718
+ }
1719
+ if (beforeShellExecution?.length) {
1720
+ hooks.beforeShellExecution = beforeShellExecution.map((h) => ({
1721
+ command: h.command
1722
+ }));
1723
+ }
1724
+ if (beforeMCPExecution?.length) {
1725
+ hooks.beforeMCPExecution = beforeMCPExecution.map((h) => ({
1726
+ command: h.command
1727
+ }));
1728
+ }
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 }
1741
+ });
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]
1747
+ });
1748
+ }
1749
+ if (settings?.indexingIgnorePatterns && settings.indexingIgnorePatterns.length > 0) {
1750
+ new import_textfile3.TextFile(component, ".cursorindexingignore", {
1751
+ lines: [GENERATED_MARKER2, "", ...settings.indexingIgnorePatterns]
1752
+ });
1753
+ }
1754
+ }
1755
+ };
1756
+
1757
+ // src/agent/agent-config.ts
1758
+ var AgentConfig = class _AgentConfig extends import_projen7.Component {
1759
+ /**
1760
+ * Find the AgentConfig component on a project.
1761
+ */
1762
+ static of(project) {
1763
+ const isAgentConfig = (c) => c instanceof _AgentConfig;
1764
+ return project.components.find(isAgentConfig);
1765
+ }
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);
1802
+ }
1803
+ }
1804
+ resolvePlatforms() {
1805
+ return this.options.platforms ?? [AGENT_PLATFORM.CURSOR, AGENT_PLATFORM.CLAUDE];
1806
+ }
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);
1818
+ }
1819
+ }
1820
+ }
1821
+ }
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);
1828
+ }
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
+ }
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);
1864
+ });
1865
+ }
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
+ }
1875
+ }
432
1876
  }
433
- });
434
- super.preSynthesize();
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()];
435
1884
  }
436
- };
437
- _TurboRepo.buildWorkflowOptions = (remoteCacheOptions) => {
438
- return {
439
- env: {
440
- GIT_BRANCH_NAME: "${{ github.head_ref || github.ref_name }}"
441
- },
442
- permissions: {
443
- contents: import_workflows_model.JobPermission.WRITE,
444
- idToken: import_workflows_model.JobPermission.WRITE
445
- },
446
- preBuildSteps: [
447
- {
448
- name: "AWS Creds for SSM",
449
- uses: "aws-actions/configure-aws-credentials@v4",
450
- with: {
451
- ["role-to-assume"]: remoteCacheOptions.oidcRole,
452
- ["aws-region"]: "us-east-1",
453
- ["role-duration-seconds"]: "900"
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
+ }
454
1894
  }
455
1895
  }
456
- ]
457
- };
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
+ }
458
1904
  };
459
- var TurboRepo = _TurboRepo;
460
1905
 
461
1906
  // src/aws/aws-deployment-config.ts
462
- var AwsDeploymentConfig = class _AwsDeploymentConfig extends import_projen.Component {
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 {
463
1911
  constructor(project) {
464
1912
  super(project);
465
1913
  /**
@@ -514,17 +1962,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends import_projen.Compo
514
1962
  */
515
1963
  get prodTargets() {
516
1964
  return this.awsDeploymentTargets.filter(
517
- (target) => target.awsStageType === import_utils.AWS_STAGE_TYPE.PROD
1965
+ (target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD
518
1966
  );
519
1967
  }
520
1968
  get prodTargetsForCI() {
521
1969
  return this.awsDeploymentTargets.filter(
522
- (target) => target.awsStageType === import_utils.AWS_STAGE_TYPE.PROD && target.ciDeployment
1970
+ (target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD && target.ciDeployment
523
1971
  );
524
1972
  }
525
1973
  get prodTargetsForLocal() {
526
1974
  return this.awsDeploymentTargets.filter(
527
- (target) => target.awsStageType === import_utils.AWS_STAGE_TYPE.PROD && target.localDeployment
1975
+ (target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD && target.localDeployment
528
1976
  );
529
1977
  }
530
1978
  /**
@@ -533,17 +1981,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends import_projen.Compo
533
1981
  */
534
1982
  get stageTargets() {
535
1983
  return this.awsDeploymentTargets.filter(
536
- (target) => target.awsStageType === import_utils.AWS_STAGE_TYPE.STAGE
1984
+ (target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE
537
1985
  );
538
1986
  }
539
1987
  get stageTargetsForCI() {
540
1988
  return this.awsDeploymentTargets.filter(
541
- (target) => target.awsStageType === import_utils.AWS_STAGE_TYPE.STAGE && target.ciDeployment
1989
+ (target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE && target.ciDeployment
542
1990
  );
543
1991
  }
544
1992
  get stageTargetsForLocal() {
545
1993
  return this.awsDeploymentTargets.filter(
546
- (target) => target.awsStageType === import_utils.AWS_STAGE_TYPE.STAGE && target.localDeployment
1994
+ (target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE && target.localDeployment
547
1995
  );
548
1996
  }
549
1997
  /**
@@ -552,17 +2000,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends import_projen.Compo
552
2000
  */
553
2001
  get devTargets() {
554
2002
  return this.awsDeploymentTargets.filter(
555
- (target) => target.awsStageType === import_utils.AWS_STAGE_TYPE.DEV
2003
+ (target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV
556
2004
  );
557
2005
  }
558
2006
  get devTargetsForCI() {
559
2007
  return this.awsDeploymentTargets.filter(
560
- (target) => target.awsStageType === import_utils.AWS_STAGE_TYPE.DEV && target.ciDeployment
2008
+ (target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV && target.ciDeployment
561
2009
  );
562
2010
  }
563
2011
  get devTargetsForLocal() {
564
2012
  return this.awsDeploymentTargets.filter(
565
- (target) => target.awsStageType === import_utils.AWS_STAGE_TYPE.DEV && target.localDeployment
2013
+ (target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV && target.localDeployment
566
2014
  );
567
2015
  }
568
2016
  preSynthesize() {
@@ -575,9 +2023,9 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends import_projen.Compo
575
2023
  };
576
2024
 
577
2025
  // src/aws/aws-deployment-target.ts
578
- var import_utils2 = __toESM(require_lib());
579
- var import_projen2 = require("projen");
580
- var AwsDeploymentTarget = class _AwsDeploymentTarget extends import_projen2.Component {
2026
+ var import_utils9 = __toESM(require_lib());
2027
+ var import_projen9 = require("projen");
2028
+ var AwsDeploymentTarget = class _AwsDeploymentTarget extends import_projen9.Component {
581
2029
  constructor(project, options) {
582
2030
  super(project);
583
2031
  /**
@@ -642,11 +2090,11 @@ var AwsDeploymentTarget = class _AwsDeploymentTarget extends import_projen2.Comp
642
2090
  };
643
2091
  this.account = options.account;
644
2092
  this.region = options.region;
645
- this.awsStageType = options.awsStageType || import_utils2.AWS_STAGE_TYPE.DEV;
646
- const role = options.deploymentTargetRole ?? options.awsEnvironmentType ?? import_utils2.DEPLOYMENT_TARGET_ROLE.PRIMARY;
2093
+ this.awsStageType = options.awsStageType || import_utils9.AWS_STAGE_TYPE.DEV;
2094
+ const role = options.deploymentTargetRole ?? options.awsEnvironmentType ?? import_utils9.DEPLOYMENT_TARGET_ROLE.PRIMARY;
647
2095
  this.deploymentTargetRole = role;
648
2096
  this.awsEnvironmentType = role;
649
- this.branches = options.branches ?? (this.awsStageType === import_utils2.AWS_STAGE_TYPE.PROD ? [
2097
+ this.branches = options.branches ?? (this.awsStageType === import_utils9.AWS_STAGE_TYPE.PROD ? [
650
2098
  {
651
2099
  branch: "main"
652
2100
  }
@@ -655,7 +2103,7 @@ var AwsDeploymentTarget = class _AwsDeploymentTarget extends import_projen2.Comp
655
2103
  branch: "feature/*"
656
2104
  }
657
2105
  ]);
658
- this.localDeployment = options.localDeployment ?? this.awsStageType === import_utils2.AWS_STAGE_TYPE.DEV;
2106
+ this.localDeployment = options.localDeployment ?? this.awsStageType === import_utils9.AWS_STAGE_TYPE.DEV;
659
2107
  if (this.localDeployment) {
660
2108
  const roleName = options.localDeploymentConfig?.roleName?.toLowerCase() || "poweruseraccess";
661
2109
  const profile = options.localDeploymentConfig?.profile || `${roleName}-${this.awsStageType}-${this.account}-${this.region}`;
@@ -790,61 +2238,14 @@ var VERSION_KEYS_SKIP = [
790
2238
  // Pinned to 3.x for Vite 5 compatibility; skip until ESM-only (issue #142)
791
2239
  ];
792
2240
 
793
- // src/versions.ts
794
- var VERSION = {
795
- /**
796
- * CDK CLI for workflows and command line operations.
797
- *
798
- * CLI and lib are versioned separately, so this is the CLI version.
799
- */
800
- AWS_CDK_CLI_VERSION: "2.1117.0",
801
- /**
802
- * CDK Version to use for construct projects.
803
- *
804
- * CLI and lib are versioned separately, so this is the lib version.
805
- */
806
- AWS_CDK_LIB_VERSION: "2.248.0",
807
- /**
808
- * Version of the AWS Constructs library to use.
809
- */
810
- AWS_CONSTRUCTS_VERSION: "10.6.0",
811
- /**
812
- * Version of Node.js to use in CI workflows at github actions.
813
- */
814
- NODE_WORKFLOWS: "24",
815
- /**
816
- * Version of PNPM to use in workflows at github actions.
817
- */
818
- PNPM_VERSION: "10.33.0",
819
- /**
820
- * Version of Projen to use.
821
- */
822
- PROJEN_VERSION: "0.99.34",
823
- /**
824
- * What version of the turborepo library should we use?
825
- */
826
- TURBO_VERSION: "2.9.4",
827
- /**
828
- * What version of Vite to use (pnpm override). Pinned to 5.x so Vitest 4.x
829
- * can load config (Vite 6+/7+ are ESM-only; see issue #142). Remove override
830
- * when moving to ESM-only test setup.
831
- */
832
- VITE_VERSION: "5.4.11",
833
- /**
834
- * What version of Vitest to use when testRunner is 'vitest'.
835
- * Pinned to 3.x so it works with Vite 5 (Vitest 4 requires Vite 6). See issue #142.
836
- */
837
- VITEST_VERSION: "3.2.4"
838
- };
839
-
840
2241
  // src/jsii/jsii-faker.ts
841
2242
  var spec = __toESM(require("@jsii/spec"));
842
- var import_projen3 = require("projen");
2243
+ var import_projen10 = require("projen");
843
2244
  var ProjenBaseFqn = {
844
2245
  TYPESCRIPT_PROJECT: "projen.typescript.TypeScriptProject",
845
2246
  TYPESCRIPT_PROJECT_OPTIONS: "projen.typescript.TypeScriptProjectOptions"
846
2247
  };
847
- var JsiiFaker = class _JsiiFaker extends import_projen3.Component {
2248
+ var JsiiFaker = class _JsiiFaker extends import_projen10.Component {
848
2249
  constructor(project) {
849
2250
  super(project);
850
2251
  this.project = project;
@@ -855,7 +2256,7 @@ var JsiiFaker = class _JsiiFaker extends import_projen3.Component {
855
2256
  };
856
2257
  };
857
2258
  this._assemblyName = this.project.package.packageName;
858
- new import_projen3.JsonFile(project, ".jsii", {
2259
+ new import_projen10.JsonFile(project, ".jsii", {
859
2260
  obj: () => {
860
2261
  return {
861
2262
  name: this._assemblyName,
@@ -892,192 +2293,24 @@ var JsiiFaker = class _JsiiFaker extends import_projen3.Component {
892
2293
  }
893
2294
  };
894
2295
 
895
- // src/pnpm/pnpm-workspace.ts
896
- var import_path = require("path");
897
- var import_projen4 = require("projen");
898
- var MIMIMUM_RELEASE_AGE = {
899
- ZERO_DAYS: 0,
900
- ONE_HOUR: 60,
901
- SIX_HOURS: 360,
902
- TWELVE_HOURS: 720,
903
- ONE_DAY: 1440,
904
- TWO_DAYS: 2880,
905
- THREE_DAYS: 4320,
906
- FOUR_DAYS: 5760,
907
- FIVE_DAYS: 7200,
908
- SIX_DAYS: 8640,
909
- ONE_WEEK: 10080
910
- };
911
- var PnpmWorkspace = class _PnpmWorkspace extends import_projen4.Component {
912
- /**
913
- * Get the pnpm workspace component of a project. If it does not exist,
914
- * return undefined.
915
- *
916
- * @param project
917
- * @returns
918
- */
919
- static of(project) {
920
- const isDefined = (c) => c instanceof _PnpmWorkspace;
921
- return project.root.components.find(isDefined);
922
- }
923
- constructor(project, options = {}) {
924
- super(project);
925
- project.tryFindObjectFile("package.json")?.addDeletionOverride("pnpm");
926
- this.fileName = options.fileName ?? "pnpm-workspace.yaml";
927
- this.minimumReleaseAge = options.minimumReleaseAge ?? MIMIMUM_RELEASE_AGE.ONE_DAY;
928
- this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude ? ["@codedrifters/*", ...options.minimumReleaseAgeExclude] : ["@codedrifters/*"];
929
- this.onlyBuiltDependencies = options.onlyBuiltDependencies ? options.onlyBuiltDependencies : [];
930
- this.ignoredBuiltDependencies = options.ignoredBuiltDependencies ? options.ignoredBuiltDependencies : [];
931
- this.subprojects = options.subprojects ?? [];
932
- this.defaultCatalog = options.defaultCatalog;
933
- this.namedCatalogs = options.namedCatalogs;
934
- project.addPackageIgnore(this.fileName);
935
- new import_projen4.YamlFile(this.project, this.fileName, {
936
- obj: () => {
937
- const pnpmConfig = {};
938
- const packages = new Array();
939
- for (const subproject of project.subprojects) {
940
- packages.push((0, import_path.relative)(this.project.outdir, subproject.outdir));
941
- }
942
- const packageSet = new Set(packages);
943
- for (const subprojectPath of this.subprojects) {
944
- packageSet.add(subprojectPath);
945
- }
946
- if (this.subprojects.length > 0) {
947
- packages.length = 0;
948
- packages.push(...packageSet);
949
- }
950
- pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;
951
- if (this.minimumReleaseAgeExclude.length > 0) {
952
- pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;
953
- }
954
- if (this.onlyBuiltDependencies.length > 0) {
955
- pnpmConfig.onlyBuiltDependencies = this.onlyBuiltDependencies;
956
- }
957
- if (this.ignoredBuiltDependencies.length > 0) {
958
- pnpmConfig.ignoreBuiltDependencies = this.ignoredBuiltDependencies;
959
- }
960
- if (this.defaultCatalog && Object.keys(this.defaultCatalog).length > 0) {
961
- pnpmConfig.catalog = this.defaultCatalog;
962
- }
963
- if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {
964
- pnpmConfig.namedCatalogs = this.namedCatalogs;
965
- }
966
- return {
967
- ...packages.length > 0 ? { packages } : {},
968
- ...pnpmConfig ? { ...pnpmConfig } : {}
969
- };
970
- }
971
- });
972
- }
973
- };
974
-
975
2296
  // src/projects/monorepo-project.ts
976
2297
  var import_javascript3 = require("projen/lib/javascript");
977
- var import_typescript = require("projen/lib/typescript");
2298
+ var import_typescript3 = require("projen/lib/typescript");
978
2299
  var import_ts_deepmerge2 = require("ts-deepmerge");
979
2300
 
980
2301
  // src/tasks/reset-task.ts
981
- var import_projen7 = require("projen");
2302
+ var import_projen12 = require("projen");
982
2303
 
983
2304
  // src/projects/typescript-project.ts
984
- var import_projen6 = require("projen");
2305
+ var import_projen11 = require("projen");
985
2306
  var import_javascript2 = require("projen/lib/javascript");
986
2307
  var import_release = require("projen/lib/release");
987
2308
  var import_ts_deepmerge = require("ts-deepmerge");
988
-
989
- // src/vitest/vitest-component.ts
990
- var import_projen5 = require("projen");
991
- var import_javascript = require("projen/lib/javascript");
992
- var import_textfile = require("projen/lib/textfile");
993
- var Vitest = class _Vitest extends import_projen5.Component {
994
- constructor(project, options = {}) {
995
- super(project);
996
- this.project = project;
997
- this.configFilePath = options.configFilePath ?? "vitest.config.ts";
998
- const config = options.config ?? {};
999
- this.include = config.include ?? ["**/*.{test,spec}.?(c|m)[jt]s?(x)"];
1000
- this.exclude = config.exclude ?? [
1001
- "**/node_modules/**",
1002
- "**/dist/**",
1003
- "**/lib/**",
1004
- "**/.?*"
1005
- ];
1006
- this.environment = config.environment ?? "node";
1007
- this.passWithNoTests = config.passWithNoTests ?? true;
1008
- this.coverageEnabled = config.coverageEnabled ?? true;
1009
- this.coverageDirectory = config.coverageDirectory ?? "coverage";
1010
- this.coverageReporters = config.coverageReporters ?? ["text", "lcov"];
1011
- this.version = options.vitestVersion ?? VERSION.VITEST_VERSION;
1012
- project.addDevDeps(`vitest@${this.version}`);
1013
- if (this.coverageEnabled) {
1014
- project.addDevDeps(`@vitest/coverage-v8@${this.version}`);
1015
- }
1016
- const coveragePath = `/${this.coverageDirectory}/`;
1017
- project.gitignore.addPatterns(coveragePath);
1018
- project.npmignore?.exclude(coveragePath);
1019
- this.addTestTasks();
1020
- this.synthesizeConfig();
1021
- }
1022
- /**
1023
- * Find the Vitest component on a project.
1024
- */
1025
- static of(project) {
1026
- const isVitest = (c) => c instanceof _Vitest;
1027
- return project.components.find(isVitest);
1028
- }
1029
- preSynthesize() {
1030
- super.preSynthesize();
1031
- for (const component of this.project.components) {
1032
- if (component instanceof import_javascript.Jest) {
1033
- throw new Error("Vitest cannot be used together with Jest");
1034
- }
1035
- }
1036
- }
1037
- addTestTasks() {
1038
- this.project.testTask.exec("vitest run --update");
1039
- if (!this.project.tasks.tryFind("test:watch")) {
1040
- this.project.addTask("test:watch", {
1041
- description: "Run tests in watch mode",
1042
- exec: "vitest watch",
1043
- receiveArgs: true
1044
- });
1045
- }
1046
- }
1047
- synthesizeConfig() {
1048
- this.project.tryRemoveFile(this.configFilePath);
1049
- new import_textfile.TextFile(this, this.configFilePath, {
1050
- lines: this.renderConfig()
1051
- });
1052
- }
1053
- renderConfig() {
1054
- return [
1055
- 'import { defineConfig } from "vitest/config";',
1056
- "",
1057
- "export default defineConfig({",
1058
- " test: {",
1059
- ` include: ${JSON.stringify(this.include)},`,
1060
- ` exclude: ${JSON.stringify(this.exclude)},`,
1061
- ` environment: "${this.environment}",`,
1062
- ` passWithNoTests: ${this.passWithNoTests},`,
1063
- " coverage: {",
1064
- ` enabled: ${this.coverageEnabled},`,
1065
- ` provider: "v8",`,
1066
- ` reportsDirectory: "${this.coverageDirectory}",`,
1067
- ` reporter: ${JSON.stringify(this.coverageReporters)},`,
1068
- " },",
1069
- " },",
1070
- "});"
1071
- ];
1072
- }
1073
- };
1074
-
1075
- // src/projects/typescript-project.ts
1076
2309
  var TestRunner = {
1077
2310
  JEST: "jest",
1078
2311
  VITEST: "vitest"
1079
2312
  };
1080
- var TypeScriptProject = class extends import_projen6.typescript.TypeScriptProject {
2313
+ var TypeScriptProject = class extends import_projen11.typescript.TypeScriptProject {
1081
2314
  constructor(userOptions) {
1082
2315
  const pnpmVersion = userOptions.parent && userOptions.parent instanceof MonorepoProject ? userOptions.parent.pnpmVersion : VERSION.PNPM_VERSION;
1083
2316
  const pnpmWorkspace = userOptions.parent && userOptions.parent instanceof MonorepoProject ? PnpmWorkspace.of(userOptions.parent) : void 0;
@@ -1237,7 +2470,7 @@ var TypeScriptProject = class extends import_projen6.typescript.TypeScriptProjec
1237
2470
  };
1238
2471
 
1239
2472
  // src/tasks/reset-task.ts
1240
- var ResetTask = class _ResetTask extends import_projen7.Component {
2473
+ var ResetTask = class _ResetTask extends import_projen12.Component {
1241
2474
  constructor(project, options = {}) {
1242
2475
  super(project);
1243
2476
  this.project = project;
@@ -1310,12 +2543,12 @@ var ResetTask = class _ResetTask extends import_projen7.Component {
1310
2543
  };
1311
2544
 
1312
2545
  // src/vscode/vscode.ts
1313
- var import_projen8 = require("projen");
1314
- var VSCodeConfig = class extends import_projen8.Component {
2546
+ var import_projen13 = require("projen");
2547
+ var VSCodeConfig = class extends import_projen13.Component {
1315
2548
  constructor(project) {
1316
2549
  super(project);
1317
- const vsConfig = new import_projen8.vscode.VsCode(project);
1318
- const vsSettings = new import_projen8.vscode.VsCodeSettings(vsConfig);
2550
+ const vsConfig = new import_projen13.vscode.VsCode(project);
2551
+ const vsSettings = new import_projen13.vscode.VsCodeSettings(vsConfig);
1319
2552
  vsSettings.addSetting("editor.tabSize", 2);
1320
2553
  vsSettings.addSetting("editor.detectIndentation", false);
1321
2554
  vsSettings.addSetting("editor.bracketPairColorization.enabled", true);
@@ -1459,7 +2692,7 @@ function addBuildCompleteJob(buildWorkflow) {
1459
2692
  // src/projects/monorepo-project.ts
1460
2693
  var CONFIGULATOR_PACKAGE_NAME = "@codedrifters/configulator";
1461
2694
  var postInstallDependenciesMap = /* @__PURE__ */ new WeakMap();
1462
- var MonorepoProject = class extends import_typescript.TypeScriptAppProject {
2695
+ var MonorepoProject = class extends import_typescript3.TypeScriptAppProject {
1463
2696
  constructor(userOptions) {
1464
2697
  const buildWorkflowOptions = userOptions.turboOptions?.remoteCacheOptions ? TurboRepo.buildWorkflowOptions(
1465
2698
  userOptions.turboOptions.remoteCacheOptions
@@ -1687,6 +2920,9 @@ var MonorepoProject = class extends import_typescript.TypeScriptAppProject {
1687
2920
  if (options.approveMergeUpgradeOptions) {
1688
2921
  addApproveMergeUpgradeWorkflow(this, options.approveMergeUpgradeOptions);
1689
2922
  }
2923
+ if (options.agentConfig) {
2924
+ new AgentConfig(this, options.agentConfigOptions);
2925
+ }
1690
2926
  if (this.buildWorkflow) {
1691
2927
  addBuildCompleteJob(this.buildWorkflow);
1692
2928
  }
@@ -1745,9 +2981,9 @@ var MonorepoProject = class extends import_typescript.TypeScriptAppProject {
1745
2981
 
1746
2982
  // src/typescript/typescript-config.ts
1747
2983
  var import_node_path2 = require("path");
1748
- var import_projen9 = require("projen");
2984
+ var import_projen14 = require("projen");
1749
2985
  var import_path2 = require("projen/lib/util/path");
1750
- var TypeScriptConfig = class extends import_projen9.Component {
2986
+ var TypeScriptConfig = class extends import_projen14.Component {
1751
2987
  constructor(project) {
1752
2988
  super(project);
1753
2989
  let tsPaths = {};
@@ -1774,13 +3010,13 @@ var TypeScriptConfig = class extends import_projen9.Component {
1774
3010
  };
1775
3011
 
1776
3012
  // src/workflows/aws-deploy-workflow.ts
1777
- var import_utils3 = __toESM(require_lib());
1778
- var import_projen10 = require("projen");
3013
+ var import_utils10 = __toESM(require_lib());
3014
+ var import_projen15 = require("projen");
1779
3015
  var import_build = require("projen/lib/build");
1780
3016
  var import_github = require("projen/lib/github");
1781
3017
  var import_workflows_model4 = require("projen/lib/github/workflows-model");
1782
3018
  var PROD_DEPLOY_NAME = "prod-deploy";
1783
- var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen10.Component {
3019
+ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen15.Component {
1784
3020
  constructor(project, options = {}) {
1785
3021
  super(project);
1786
3022
  this.project = project;
@@ -1791,7 +3027,7 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen10.Compone
1791
3027
  * @deprecated Use deployment target role terminology elsewhere. This property is maintained for backward compatibility.
1792
3028
  * @default 'primary' (this is the only type supported currently)
1793
3029
  */
1794
- this.awsEnvironmentType = import_utils3.DEPLOYMENT_TARGET_ROLE.PRIMARY;
3030
+ this.awsEnvironmentType = import_utils10.DEPLOYMENT_TARGET_ROLE.PRIMARY;
1795
3031
  this.setupNode = () => {
1796
3032
  return [
1797
3033
  {
@@ -1901,7 +3137,7 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen10.Compone
1901
3137
  }
1902
3138
  const turbo = TurboRepo.of(this.rootProject);
1903
3139
  const buildWorkflowOptions = turbo?.remoteCacheOptions ? TurboRepo.buildWorkflowOptions(turbo.remoteCacheOptions) : {};
1904
- this.awsStageType = options.awsStageType ?? import_utils3.AWS_STAGE_TYPE.DEV;
3140
+ this.awsStageType = options.awsStageType ?? import_utils10.AWS_STAGE_TYPE.DEV;
1905
3141
  this.awsDeploymentTargets = options.awsDeploymentTargets ?? AwsDeploymentConfig.of(project)?.awsDeploymentTargets.filter(
1906
3142
  (target) => target.awsStageType === this.awsStageType && target.ciDeployment
1907
3143
  ) ?? [];
@@ -2045,11 +3281,18 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen10.Compone
2045
3281
  };
2046
3282
  // Annotate the CommonJS export names for ESM import in node:
2047
3283
  0 && (module.exports = {
3284
+ AGENT_MODEL,
3285
+ AGENT_PLATFORM,
3286
+ AGENT_RULE_SCOPE,
3287
+ AgentConfig,
2048
3288
  AwsDeployWorkflow,
2049
3289
  AwsDeploymentConfig,
2050
3290
  AwsDeploymentTarget,
3291
+ BUILT_IN_BUNDLES,
3292
+ CLAUDE_RULE_TARGET,
2051
3293
  COMPLETE_JOB_ID,
2052
3294
  JsiiFaker,
3295
+ MCP_TRANSPORT,
2053
3296
  MERGE_METHODS,
2054
3297
  MIMIMUM_RELEASE_AGE,
2055
3298
  MonorepoProject,
@@ -2070,6 +3313,14 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen10.Compone
2070
3313
  Vitest,
2071
3314
  addApproveMergeUpgradeWorkflow,
2072
3315
  addBuildCompleteJob,
2073
- getLatestEligibleVersion
3316
+ awsCdkBundle,
3317
+ baseBundle,
3318
+ getLatestEligibleVersion,
3319
+ jestBundle,
3320
+ pnpmBundle,
3321
+ projenBundle,
3322
+ turborepoBundle,
3323
+ typescriptBundle,
3324
+ vitestBundle
2074
3325
  });
2075
3326
  //# sourceMappingURL=index.js.map