@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.mjs
CHANGED
|
@@ -173,14 +173,7 @@ var require_lib = __commonJS({
|
|
|
173
173
|
});
|
|
174
174
|
|
|
175
175
|
// src/agent/agent-config.ts
|
|
176
|
-
import { Component as
|
|
177
|
-
|
|
178
|
-
// src/agent/bundles/index.ts
|
|
179
|
-
var BUILT_IN_BUNDLES = [];
|
|
180
|
-
|
|
181
|
-
// src/agent/renderers/claude-renderer.ts
|
|
182
|
-
import { JsonFile } from "projen";
|
|
183
|
-
import { TextFile } from "projen/lib/textfile";
|
|
176
|
+
import { Component as Component7 } from "projen";
|
|
184
177
|
|
|
185
178
|
// src/agent/types.ts
|
|
186
179
|
var AGENT_RULE_SCOPE = {
|
|
@@ -210,7 +203,1062 @@ var MCP_TRANSPORT = {
|
|
|
210
203
|
SSE: "sse"
|
|
211
204
|
};
|
|
212
205
|
|
|
206
|
+
// src/agent/bundles/utils.ts
|
|
207
|
+
function hasComponent(project, ctor) {
|
|
208
|
+
if (project.components.some((c) => c instanceof ctor)) return true;
|
|
209
|
+
return project.subprojects.some(
|
|
210
|
+
(sub) => sub.components.some((c) => c instanceof ctor)
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
function hasDep(project, name) {
|
|
214
|
+
if (project.deps.all.some((d) => d.name === name)) return true;
|
|
215
|
+
return project.subprojects.some(
|
|
216
|
+
(sub) => sub.deps.all.some((d) => d.name === name)
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
function hasFile(project, filename) {
|
|
220
|
+
if (project.tryFindFile(filename) !== void 0) return true;
|
|
221
|
+
return project.subprojects.some(
|
|
222
|
+
(sub) => sub.tryFindFile(filename) !== void 0
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/agent/bundles/aws-cdk.ts
|
|
227
|
+
var awsCdkBundle = {
|
|
228
|
+
name: "aws-cdk",
|
|
229
|
+
description: "AWS CDK construct patterns, L2/L3 conventions, IAM best practices",
|
|
230
|
+
appliesWhen: (project) => hasDep(project, "aws-cdk-lib"),
|
|
231
|
+
rules: [
|
|
232
|
+
{
|
|
233
|
+
name: "aws-cdk-conventions",
|
|
234
|
+
description: "AWS CDK construct patterns and best practices",
|
|
235
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
236
|
+
filePatterns: ["**/*.ts"],
|
|
237
|
+
content: [
|
|
238
|
+
"# AWS CDK Conventions",
|
|
239
|
+
"",
|
|
240
|
+
"## Construct Structure",
|
|
241
|
+
"",
|
|
242
|
+
"- All constructs extend `Construct` from `constructs`",
|
|
243
|
+
"- Use `readonly` for all props interfaces",
|
|
244
|
+
"- Include minimal JSDoc for configuration options",
|
|
245
|
+
"- Follow AWS CDK best practices for resource naming and organization",
|
|
246
|
+
"- Use proper TypeScript types from `aws-cdk-lib`",
|
|
247
|
+
"- Export constructs from `index.ts` for public API",
|
|
248
|
+
"",
|
|
249
|
+
"## CDK Construct Pattern",
|
|
250
|
+
"",
|
|
251
|
+
"```typescript",
|
|
252
|
+
"export interface MyConstructProps {",
|
|
253
|
+
" /** Brief description. */",
|
|
254
|
+
" readonly myProperty: string;",
|
|
255
|
+
"}",
|
|
256
|
+
"",
|
|
257
|
+
"export class MyConstruct extends Construct {",
|
|
258
|
+
" constructor(scope: Construct, id: string, props: MyConstructProps) {",
|
|
259
|
+
" super(scope, id);",
|
|
260
|
+
" // Implementation",
|
|
261
|
+
" }",
|
|
262
|
+
"}",
|
|
263
|
+
"```",
|
|
264
|
+
"",
|
|
265
|
+
"## AWS Best Practices",
|
|
266
|
+
"",
|
|
267
|
+
"- Use AWS CDK v2 (`aws-cdk-lib`)",
|
|
268
|
+
"- Follow AWS best practices for security and resource configuration",
|
|
269
|
+
"- Use proper IAM permissions (principle of least privilege)",
|
|
270
|
+
"- Include proper tags and descriptions for resources",
|
|
271
|
+
"- Use SSM parameters for cross-stack references when needed",
|
|
272
|
+
"- Do not pass values between stacks; use SSM parameters instead",
|
|
273
|
+
"",
|
|
274
|
+
"## CDK Testing",
|
|
275
|
+
"",
|
|
276
|
+
"- Mock `Code.fromAsset` in any test file that synthesizes CDK stacks",
|
|
277
|
+
"- Use static S3 values (`mock-assets-bucket`, `mock-asset-key.zip`) so snapshots are stable",
|
|
278
|
+
"- Add the mock in `beforeAll` and restore in `afterAll`",
|
|
279
|
+
"- Normalize the template before snapshotting when the stack includes asset-based Lambdas"
|
|
280
|
+
].join("\n"),
|
|
281
|
+
tags: ["infrastructure"]
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
// src/agent/bundles/base.ts
|
|
287
|
+
var baseBundle = {
|
|
288
|
+
name: "base",
|
|
289
|
+
description: "Core rules: project overview, interaction style, and general coding conventions",
|
|
290
|
+
appliesWhen: () => true,
|
|
291
|
+
rules: [
|
|
292
|
+
{
|
|
293
|
+
name: "project-overview",
|
|
294
|
+
description: "Project context and technology stack overview",
|
|
295
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
296
|
+
content: [
|
|
297
|
+
"# Project Overview",
|
|
298
|
+
"",
|
|
299
|
+
"## Important Notes",
|
|
300
|
+
"",
|
|
301
|
+
"- **Never edit generated files** \u2014 they are marked with `// ~~ Generated by projen`",
|
|
302
|
+
"- **After modifying Projen configuration**, the user should run `npx projen` locally. The agent must not run `npx projen`, `pnpm install`, or `pnpm i`.",
|
|
303
|
+
"- **Configure dependencies through Projen** \u2014 never use `npm install`, `pnpm add`, or `yarn add`. Add them to `deps` or `devDeps` in Projen config.",
|
|
304
|
+
"- **Export from index.ts** to maintain clean public APIs"
|
|
305
|
+
].join("\n"),
|
|
306
|
+
tags: ["project"]
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
name: "interaction-style",
|
|
310
|
+
description: "Interaction style \u2014 ask questions one at a time and wait for feedback",
|
|
311
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
312
|
+
content: [
|
|
313
|
+
"# Interaction Style Guidelines",
|
|
314
|
+
"",
|
|
315
|
+
"When responding to requests, follow these interaction principles.",
|
|
316
|
+
"",
|
|
317
|
+
"1. **Ask questions one at a time**: When clarification is needed, ask a single question and wait for the user's response before proceeding.",
|
|
318
|
+
"2. **Wait for feedback**: After asking a question, pause and wait for the user's answer before asking additional questions or making assumptions.",
|
|
319
|
+
"3. **Avoid question overload**: Do not ask multiple questions in a single response. If multiple clarifications are needed, prioritize the most important question first.",
|
|
320
|
+
"4. **Progressive clarification**: Once the user answers your first question, you may then ask the next most important question if needed.",
|
|
321
|
+
"5. **Confirm understanding**: After receiving feedback, acknowledge the user's response before proceeding with the next step or question.",
|
|
322
|
+
"6. **Be patient**: Do not rush ahead with assumptions. It is better to ask one clarifying question than to proceed with incorrect assumptions."
|
|
323
|
+
].join("\n"),
|
|
324
|
+
tags: ["project"]
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
name: "general-conventions",
|
|
328
|
+
description: "Code formatting (Prettier/ESLint), import conventions (ES modules, import order), error handling (async/await, no floating promises)",
|
|
329
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
330
|
+
filePatterns: ["**/*.ts", "**/*.tsx"],
|
|
331
|
+
content: [
|
|
332
|
+
"# General Conventions",
|
|
333
|
+
"",
|
|
334
|
+
"## Code Formatting",
|
|
335
|
+
"",
|
|
336
|
+
"- Use **Prettier** for formatting (runs automatically on save in VS Code)",
|
|
337
|
+
"- Always use curly braces for control flow, even single-line statements",
|
|
338
|
+
"- Prefer `const` over `let`; avoid `var`",
|
|
339
|
+
"- Use trailing commas in multi-line objects/arrays",
|
|
340
|
+
"",
|
|
341
|
+
"### ESLint Rules to Follow",
|
|
342
|
+
"",
|
|
343
|
+
"- `curly`: Always use curly braces (multi-line, consistent)",
|
|
344
|
+
"- `dot-notation`: Use dot notation over bracket notation",
|
|
345
|
+
"- `no-bitwise`: No bitwise operators",
|
|
346
|
+
"- `@typescript-eslint/no-shadow`: No variable shadowing",
|
|
347
|
+
"- `@typescript-eslint/member-ordering`: Follow member order",
|
|
348
|
+
"",
|
|
349
|
+
"## Import Conventions",
|
|
350
|
+
"",
|
|
351
|
+
"- **Always use ES modules** (`import`/`export`), never `require()`",
|
|
352
|
+
"- Import order:",
|
|
353
|
+
" 1. Built-in Node.js modules (e.g., `node:path`, `node:fs`)",
|
|
354
|
+
" 2. External dependencies (alphabetically sorted)",
|
|
355
|
+
" 3. Internal imports (relative paths)",
|
|
356
|
+
"- Group imports with blank lines between groups",
|
|
357
|
+
"- Alphabetize imports within each group (case-insensitive)",
|
|
358
|
+
"",
|
|
359
|
+
"## Error Handling",
|
|
360
|
+
"",
|
|
361
|
+
"- Always handle promises properly with `await`",
|
|
362
|
+
"- Use `@typescript-eslint/return-await` rule (always return await)",
|
|
363
|
+
"- Never leave floating promises (`@typescript-eslint/no-floating-promises`)",
|
|
364
|
+
"- Use proper error types and meaningful error messages",
|
|
365
|
+
"- Do not swallow errors or use empty catch blocks",
|
|
366
|
+
"- Prefer async/await over raw promises"
|
|
367
|
+
].join("\n"),
|
|
368
|
+
tags: ["coding"]
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: "pull-request-conventions",
|
|
372
|
+
description: "Conventional commit PR titles, closing keywords, change summaries",
|
|
373
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
374
|
+
content: [
|
|
375
|
+
"# Pull Request Conventions",
|
|
376
|
+
"",
|
|
377
|
+
"## PR Title Prefix",
|
|
378
|
+
"",
|
|
379
|
+
"**Always** use a **conventional commit prefix** in the PR `title`. Format: `type: description` or `type(scope): description`.",
|
|
380
|
+
"",
|
|
381
|
+
"| Prefix | Use for |",
|
|
382
|
+
"|--------|---------|",
|
|
383
|
+
"| `feat:` | New features or functionality |",
|
|
384
|
+
"| `fix:` | Bug fixes |",
|
|
385
|
+
"| `docs:` | Documentation-only changes |",
|
|
386
|
+
"| `chore:` | Maintenance: deps, tooling, config |",
|
|
387
|
+
"| `refactor:` | Code restructure, no behavior change |",
|
|
388
|
+
"| `release:` | Release preparation, version bumps |",
|
|
389
|
+
"| `hotfix:` | Urgent production fixes |",
|
|
390
|
+
"",
|
|
391
|
+
"## Link to the Issue",
|
|
392
|
+
"",
|
|
393
|
+
"When the PR addresses an issue, **always** include a closing keyword in the PR body:",
|
|
394
|
+
"- `Closes #<issue>`, `Fixes #<issue>`, or `Resolves #<issue>`",
|
|
395
|
+
"",
|
|
396
|
+
"## Summary of Changes",
|
|
397
|
+
"",
|
|
398
|
+
"Every PR must include a **summary of the changes** made. Use bullet points or short paragraphs. Do not leave the description empty.",
|
|
399
|
+
"",
|
|
400
|
+
"## Commit Messages",
|
|
401
|
+
"",
|
|
402
|
+
"Use **conventional commits** for git commit messages: `type: short description`. Do not add AI co-author or attribution."
|
|
403
|
+
].join("\n"),
|
|
404
|
+
tags: ["workflow"]
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
name: "branch-naming-conventions",
|
|
408
|
+
description: "Branch format (type/[issue-]description), create-on-GitHub-then-fetch workflow",
|
|
409
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
410
|
+
content: [
|
|
411
|
+
"# Branch Naming Conventions",
|
|
412
|
+
"",
|
|
413
|
+
"## Format",
|
|
414
|
+
"",
|
|
415
|
+
"```",
|
|
416
|
+
"<type>/[<issue>-]<description>",
|
|
417
|
+
"```",
|
|
418
|
+
"",
|
|
419
|
+
"- **type** (required): One of `feat`, `fix`, `docs`, `chore`, `refactor`, `release`, `hotfix`",
|
|
420
|
+
"- **issue** (optional): Issue number (e.g., `25`). Include when known.",
|
|
421
|
+
"- **description** (required): Short, lowercase, kebab-case summary",
|
|
422
|
+
"",
|
|
423
|
+
"## Examples",
|
|
424
|
+
"",
|
|
425
|
+
"- `feat/25-add-cursor-rules`",
|
|
426
|
+
"- `fix/23-rename-cursor-rules-mdc`",
|
|
427
|
+
"- `chore/upgrade-eslint`",
|
|
428
|
+
"- `docs/update-readme`"
|
|
429
|
+
].join("\n"),
|
|
430
|
+
tags: ["workflow"]
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
name: "issue-conventions",
|
|
434
|
+
description: "Issue title prefixes, GitHub issue type mapping, prerequisite issues",
|
|
435
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
436
|
+
content: [
|
|
437
|
+
"# Issue Title Conventions",
|
|
438
|
+
"",
|
|
439
|
+
"## Format",
|
|
440
|
+
"",
|
|
441
|
+
"```",
|
|
442
|
+
"<type>: <description>",
|
|
443
|
+
"```",
|
|
444
|
+
"",
|
|
445
|
+
"## Types",
|
|
446
|
+
"",
|
|
447
|
+
"| Prefix | Use for |",
|
|
448
|
+
"|--------|---------|",
|
|
449
|
+
"| `epic:` | Large initiatives spanning multiple child issues |",
|
|
450
|
+
"| `feat:` | New features or functionality |",
|
|
451
|
+
"| `fix:` | Bug fixes |",
|
|
452
|
+
"| `chore:` | Maintenance: deps, tooling, config |",
|
|
453
|
+
"| `docs:` | Documentation-only work |",
|
|
454
|
+
"| `refactor:` | Code restructure, no behavior change |",
|
|
455
|
+
"| `release:` | Release preparation, version bumps |",
|
|
456
|
+
"| `hotfix:` | Urgent production fixes |",
|
|
457
|
+
"",
|
|
458
|
+
"## Prerequisite Issues",
|
|
459
|
+
"",
|
|
460
|
+
"Include any prerequisite (blocking) issues in the issue body when they exist.",
|
|
461
|
+
"Use a **Dependencies** section or `**Depends on:** #123`."
|
|
462
|
+
].join("\n"),
|
|
463
|
+
tags: ["workflow"]
|
|
464
|
+
}
|
|
465
|
+
]
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
// src/agent/bundles/jest.ts
|
|
469
|
+
var jestBundle = {
|
|
470
|
+
name: "jest",
|
|
471
|
+
description: "Jest testing conventions and patterns",
|
|
472
|
+
appliesWhen: (project) => hasDep(project, "jest"),
|
|
473
|
+
rules: [
|
|
474
|
+
{
|
|
475
|
+
name: "jest-testing",
|
|
476
|
+
description: "Jest testing conventions and patterns",
|
|
477
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
478
|
+
filePatterns: ["**/*.test.ts", "**/*.spec.ts"],
|
|
479
|
+
content: [
|
|
480
|
+
"# Jest Testing Patterns",
|
|
481
|
+
"",
|
|
482
|
+
"## Mandatory Requirements",
|
|
483
|
+
"",
|
|
484
|
+
"- **Tests MUST be created or updated whenever code functionality is added or changed**",
|
|
485
|
+
"- This applies to all code changes, including:",
|
|
486
|
+
" - New features and functionality",
|
|
487
|
+
" - Bug fixes",
|
|
488
|
+
" - Refactoring that changes behavior",
|
|
489
|
+
" - API changes",
|
|
490
|
+
" - Configuration changes that affect functionality",
|
|
491
|
+
"- Tests should be written or updated as part of the same change that modifies the code",
|
|
492
|
+
"",
|
|
493
|
+
"## Test Structure",
|
|
494
|
+
"",
|
|
495
|
+
"- Use **Jest** with SWC for fast compilation",
|
|
496
|
+
"- Test files: `.spec.ts` or `.test.ts` (co-located with source)",
|
|
497
|
+
"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`",
|
|
498
|
+
"- Prefer snapshot tests for complex object structures",
|
|
499
|
+
"- Mock external dependencies appropriately",
|
|
500
|
+
"",
|
|
501
|
+
"## Test Organization",
|
|
502
|
+
"",
|
|
503
|
+
"- Co-locate test files with source files",
|
|
504
|
+
"- Test files can use dev dependencies (ESLint rule override)",
|
|
505
|
+
"- Use `@swc/jest` for fast compilation",
|
|
506
|
+
"- Configure Jest in `jest.config.json` (not in package.json)",
|
|
507
|
+
"",
|
|
508
|
+
"## Example Test Structure",
|
|
509
|
+
"",
|
|
510
|
+
"```typescript",
|
|
511
|
+
"import { MyClass } from './my-class';",
|
|
512
|
+
"",
|
|
513
|
+
"describe('MyClass', () => {",
|
|
514
|
+
" it('should do something specific', () => {",
|
|
515
|
+
" // Test implementation",
|
|
516
|
+
" });",
|
|
517
|
+
"});",
|
|
518
|
+
"```"
|
|
519
|
+
].join("\n"),
|
|
520
|
+
tags: ["testing"]
|
|
521
|
+
}
|
|
522
|
+
]
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
// src/pnpm/pnpm-workspace.ts
|
|
526
|
+
import { relative } from "path";
|
|
527
|
+
import { Component, YamlFile } from "projen";
|
|
528
|
+
var MIMIMUM_RELEASE_AGE = {
|
|
529
|
+
ZERO_DAYS: 0,
|
|
530
|
+
ONE_HOUR: 60,
|
|
531
|
+
SIX_HOURS: 360,
|
|
532
|
+
TWELVE_HOURS: 720,
|
|
533
|
+
ONE_DAY: 1440,
|
|
534
|
+
TWO_DAYS: 2880,
|
|
535
|
+
THREE_DAYS: 4320,
|
|
536
|
+
FOUR_DAYS: 5760,
|
|
537
|
+
FIVE_DAYS: 7200,
|
|
538
|
+
SIX_DAYS: 8640,
|
|
539
|
+
ONE_WEEK: 10080
|
|
540
|
+
};
|
|
541
|
+
var PnpmWorkspace = class _PnpmWorkspace extends Component {
|
|
542
|
+
/**
|
|
543
|
+
* Get the pnpm workspace component of a project. If it does not exist,
|
|
544
|
+
* return undefined.
|
|
545
|
+
*
|
|
546
|
+
* @param project
|
|
547
|
+
* @returns
|
|
548
|
+
*/
|
|
549
|
+
static of(project) {
|
|
550
|
+
const isDefined = (c) => c instanceof _PnpmWorkspace;
|
|
551
|
+
return project.root.components.find(isDefined);
|
|
552
|
+
}
|
|
553
|
+
constructor(project, options = {}) {
|
|
554
|
+
super(project);
|
|
555
|
+
project.tryFindObjectFile("package.json")?.addDeletionOverride("pnpm");
|
|
556
|
+
this.fileName = options.fileName ?? "pnpm-workspace.yaml";
|
|
557
|
+
this.minimumReleaseAge = options.minimumReleaseAge ?? MIMIMUM_RELEASE_AGE.ONE_DAY;
|
|
558
|
+
this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude ? ["@codedrifters/*", ...options.minimumReleaseAgeExclude] : ["@codedrifters/*"];
|
|
559
|
+
this.onlyBuiltDependencies = options.onlyBuiltDependencies ? options.onlyBuiltDependencies : [];
|
|
560
|
+
this.ignoredBuiltDependencies = options.ignoredBuiltDependencies ? options.ignoredBuiltDependencies : [];
|
|
561
|
+
this.subprojects = options.subprojects ?? [];
|
|
562
|
+
this.defaultCatalog = options.defaultCatalog;
|
|
563
|
+
this.namedCatalogs = options.namedCatalogs;
|
|
564
|
+
project.addPackageIgnore(this.fileName);
|
|
565
|
+
new YamlFile(this.project, this.fileName, {
|
|
566
|
+
obj: () => {
|
|
567
|
+
const pnpmConfig = {};
|
|
568
|
+
const packages = new Array();
|
|
569
|
+
for (const subproject of project.subprojects) {
|
|
570
|
+
packages.push(relative(this.project.outdir, subproject.outdir));
|
|
571
|
+
}
|
|
572
|
+
const packageSet = new Set(packages);
|
|
573
|
+
for (const subprojectPath of this.subprojects) {
|
|
574
|
+
packageSet.add(subprojectPath);
|
|
575
|
+
}
|
|
576
|
+
if (this.subprojects.length > 0) {
|
|
577
|
+
packages.length = 0;
|
|
578
|
+
packages.push(...packageSet);
|
|
579
|
+
}
|
|
580
|
+
pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;
|
|
581
|
+
if (this.minimumReleaseAgeExclude.length > 0) {
|
|
582
|
+
pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;
|
|
583
|
+
}
|
|
584
|
+
if (this.onlyBuiltDependencies.length > 0) {
|
|
585
|
+
pnpmConfig.onlyBuiltDependencies = this.onlyBuiltDependencies;
|
|
586
|
+
}
|
|
587
|
+
if (this.ignoredBuiltDependencies.length > 0) {
|
|
588
|
+
pnpmConfig.ignoreBuiltDependencies = this.ignoredBuiltDependencies;
|
|
589
|
+
}
|
|
590
|
+
if (this.defaultCatalog && Object.keys(this.defaultCatalog).length > 0) {
|
|
591
|
+
pnpmConfig.catalog = this.defaultCatalog;
|
|
592
|
+
}
|
|
593
|
+
if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {
|
|
594
|
+
pnpmConfig.namedCatalogs = this.namedCatalogs;
|
|
595
|
+
}
|
|
596
|
+
return {
|
|
597
|
+
...packages.length > 0 ? { packages } : {},
|
|
598
|
+
...pnpmConfig ? { ...pnpmConfig } : {}
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
// src/agent/bundles/pnpm.ts
|
|
606
|
+
var pnpmBundle = {
|
|
607
|
+
name: "pnpm",
|
|
608
|
+
description: "PNPM workspace rules and dependency management conventions",
|
|
609
|
+
appliesWhen: (project) => hasComponent(project, PnpmWorkspace),
|
|
610
|
+
rules: [
|
|
611
|
+
{
|
|
612
|
+
name: "pnpm-workspace",
|
|
613
|
+
description: "PNPM workspace and dependency management conventions",
|
|
614
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
615
|
+
filePatterns: ["package.json", "pnpm-workspace.yaml", "pnpm-lock.yaml"],
|
|
616
|
+
content: [
|
|
617
|
+
"# PNPM Workspace Conventions",
|
|
618
|
+
"",
|
|
619
|
+
"## Package Management",
|
|
620
|
+
"",
|
|
621
|
+
"- Use **PNPM** for package management",
|
|
622
|
+
"- Workspace configuration in `pnpm-workspace.yaml`",
|
|
623
|
+
"- Dependencies managed through Projen, not directly in `package.json`",
|
|
624
|
+
"- **Always use workspace dependencies** (`workspace:*` or `workspace:^`) for packages within this monorepo",
|
|
625
|
+
"- Never use published NPM versions of internal packages; always reference the local workspace version",
|
|
626
|
+
"",
|
|
627
|
+
"## Dependency Management",
|
|
628
|
+
"",
|
|
629
|
+
"**DO:**",
|
|
630
|
+
"- Configure dependencies in Projen configuration files (`.projenrc.ts` or `projenrc/*.ts`)",
|
|
631
|
+
"- Add dependencies to `deps`, `devDeps`, or `peerDeps` arrays in project configuration",
|
|
632
|
+
'- Use catalog dependencies when available (e.g., `"aws-cdk-lib@catalog:"`)',
|
|
633
|
+
"- Ask the user to run `npx projen` and `pnpm install` after updating dependency configuration",
|
|
634
|
+
"",
|
|
635
|
+
"**DO NOT:**",
|
|
636
|
+
"- Run `npm install some-package`",
|
|
637
|
+
"- Run `pnpm add some-package`",
|
|
638
|
+
"- Run `yarn add some-package`",
|
|
639
|
+
"- Manually edit `package.json` dependencies",
|
|
640
|
+
"",
|
|
641
|
+
"Manual package installation creates conflicts with Projen-managed files."
|
|
642
|
+
].join("\n"),
|
|
643
|
+
tags: ["workflow"]
|
|
644
|
+
}
|
|
645
|
+
]
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
// src/agent/bundles/projen.ts
|
|
649
|
+
var projenBundle = {
|
|
650
|
+
name: "projen",
|
|
651
|
+
description: "Projen conventions, synthesis workflow, .projenrc.ts patterns",
|
|
652
|
+
appliesWhen: (project) => hasDep(project, "projen"),
|
|
653
|
+
rules: [
|
|
654
|
+
{
|
|
655
|
+
name: "projen-conventions",
|
|
656
|
+
description: "Projen configuration patterns and best practices",
|
|
657
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
658
|
+
filePatterns: ["projenrc/**/*.ts", ".projenrc.ts"],
|
|
659
|
+
content: [
|
|
660
|
+
"# Projen Conventions",
|
|
661
|
+
"",
|
|
662
|
+
"## Configuration Management",
|
|
663
|
+
"",
|
|
664
|
+
"- **Never edit generated files** (`package.json`, `tsconfig.json`, etc. marked with `// ~~ Generated by projen`)",
|
|
665
|
+
"- Edit Projen configuration in:",
|
|
666
|
+
" - `.projenrc.ts` (root)",
|
|
667
|
+
" - `projenrc/*.ts` (package-specific)",
|
|
668
|
+
"- After making Projen changes, ask the user to run `npx projen` locally (agent must not run it)",
|
|
669
|
+
"",
|
|
670
|
+
"## Custom Projen Components",
|
|
671
|
+
"",
|
|
672
|
+
"All custom components must extend `Component` from Projen and use a static `.of()` factory for discovery:",
|
|
673
|
+
"",
|
|
674
|
+
"```typescript",
|
|
675
|
+
"export class MyComponent extends Component {",
|
|
676
|
+
" public static of(project: Project): MyComponent | undefined {",
|
|
677
|
+
" const isDefined = (c: Component): c is MyComponent =>",
|
|
678
|
+
" c instanceof MyComponent;",
|
|
679
|
+
" return project.components.find(isDefined);",
|
|
680
|
+
" }",
|
|
681
|
+
"",
|
|
682
|
+
" constructor(project: Project, options: MyComponentOptions) {",
|
|
683
|
+
" super(project);",
|
|
684
|
+
" // Implementation",
|
|
685
|
+
" }",
|
|
686
|
+
"}",
|
|
687
|
+
"```",
|
|
688
|
+
"",
|
|
689
|
+
"## Component Authoring",
|
|
690
|
+
"",
|
|
691
|
+
"- Export project types and utilities from `index.ts`",
|
|
692
|
+
"- Follow Projen's component lifecycle patterns",
|
|
693
|
+
"- Use `merge` from `ts-deepmerge` for deep merging configuration objects",
|
|
694
|
+
"- Components should be reusable and configurable; use TypeScript interfaces for component options",
|
|
695
|
+
"- Provide sensible defaults while allowing customization",
|
|
696
|
+
"- Document public APIs with minimal JSDoc; put extended documentation in markdown",
|
|
697
|
+
"",
|
|
698
|
+
"## Dependencies",
|
|
699
|
+
"",
|
|
700
|
+
"- Dependencies managed through Projen configuration, not directly in `package.json`",
|
|
701
|
+
'- Use catalog dependencies when available (e.g., `"projen": "catalog:"`)',
|
|
702
|
+
"- Peer dependencies for shared libraries (e.g., `constructs`, `projen`, `aws-cdk-lib`)",
|
|
703
|
+
'- Use workspace protocol for internal packages: `"@org/pkg@workspace:*"`'
|
|
704
|
+
].join("\n"),
|
|
705
|
+
tags: ["workflow"]
|
|
706
|
+
}
|
|
707
|
+
]
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
// src/turbo/turbo-repo.ts
|
|
711
|
+
import { Component as Component3, FileBase, JsonFile } from "projen/lib";
|
|
712
|
+
import { JobPermission } from "projen/lib/github/workflows-model";
|
|
713
|
+
|
|
714
|
+
// src/turbo/turbo-repo-task.ts
|
|
715
|
+
import { Component as Component2 } from "projen/lib";
|
|
716
|
+
var TurboRepoTask = class extends Component2 {
|
|
717
|
+
constructor(project, options) {
|
|
718
|
+
super(project);
|
|
719
|
+
this.project = project;
|
|
720
|
+
this.name = options.name;
|
|
721
|
+
this.dependsOn = options.dependsOn ?? [];
|
|
722
|
+
this.env = options.env ?? [];
|
|
723
|
+
this.passThroughEnv = options.passThroughEnv ?? [];
|
|
724
|
+
this.outputs = options.outputs ?? [];
|
|
725
|
+
this.cache = options.cache ?? true;
|
|
726
|
+
this.inputs = [
|
|
727
|
+
...options.inputs ?? [],
|
|
728
|
+
// rerun if projen config changes
|
|
729
|
+
".projen/**",
|
|
730
|
+
// ignore mac files
|
|
731
|
+
"!.DS_Store",
|
|
732
|
+
"!**/.DS_Store"
|
|
733
|
+
];
|
|
734
|
+
this.outputLogs = options.outputLogs ?? "new-only";
|
|
735
|
+
this.persistent = options.persistent ?? false;
|
|
736
|
+
this.interactive = options.interactive ?? false;
|
|
737
|
+
this.isActive = true;
|
|
738
|
+
}
|
|
739
|
+
taskConfig() {
|
|
740
|
+
return {
|
|
741
|
+
dependsOn: this.dependsOn,
|
|
742
|
+
env: this.env,
|
|
743
|
+
passThroughEnv: this.passThroughEnv,
|
|
744
|
+
outputs: this.outputs,
|
|
745
|
+
cache: this.cache,
|
|
746
|
+
inputs: this.inputs,
|
|
747
|
+
outputLogs: this.outputLogs,
|
|
748
|
+
persistent: this.persistent,
|
|
749
|
+
interactive: this.interactive
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
// src/turbo/turbo-repo.ts
|
|
755
|
+
var ROOT_TURBO_TASK_NAME = "turbo:build";
|
|
756
|
+
var ROOT_CI_TASK_NAME = "build:all";
|
|
757
|
+
var _TurboRepo = class _TurboRepo extends Component3 {
|
|
758
|
+
constructor(project, options = {}) {
|
|
759
|
+
super(project);
|
|
760
|
+
this.project = project;
|
|
761
|
+
/**
|
|
762
|
+
* Sub-Tasks to run
|
|
763
|
+
*/
|
|
764
|
+
this.tasks = [];
|
|
765
|
+
this.turboVersion = options.turboVersion ?? "catalog:";
|
|
766
|
+
this.isRootProject = project === project.root;
|
|
767
|
+
if (this.isRootProject) {
|
|
768
|
+
project.addDevDeps(`turbo@${this.turboVersion}`);
|
|
769
|
+
}
|
|
770
|
+
project.gitignore.addPatterns("/.turbo");
|
|
771
|
+
project.npmignore?.addPatterns("/.turbo/");
|
|
772
|
+
this.extends = options.extends ?? (this.isRootProject ? [] : ["//"]);
|
|
773
|
+
this.globalDependencies = options.globalDependencies ?? [];
|
|
774
|
+
this.globalEnv = options.globalEnv ?? [];
|
|
775
|
+
this.globalPassThroughEnv = options.globalPassThroughEnv ?? [];
|
|
776
|
+
this.ui = options.ui ?? "stream";
|
|
777
|
+
this.dangerouslyDisablePackageManagerCheck = options.dangerouslyDisablePackageManagerCheck ?? false;
|
|
778
|
+
this.cacheDir = options.cacheDir ?? ".turbo/cache";
|
|
779
|
+
this.daemon = options.daemon ?? true;
|
|
780
|
+
this.envMode = options.envMode ?? "strict";
|
|
781
|
+
this.remoteCacheOptions = options.remoteCacheOptions;
|
|
782
|
+
this.buildAllTaskEnvVars = options.buildAllTaskEnvVars ?? {};
|
|
783
|
+
const rootGeneratedFiles = this.isRootProject ? this.project.components.filter((c) => c instanceof FileBase).map((c) => c.path) : [];
|
|
784
|
+
this.buildTask = new TurboRepoTask(this.project, {
|
|
785
|
+
name: ROOT_TURBO_TASK_NAME,
|
|
786
|
+
dependsOn: this.isRootProject ? [`^${ROOT_TURBO_TASK_NAME}`] : [],
|
|
787
|
+
...rootGeneratedFiles.length > 0 && { inputs: rootGeneratedFiles }
|
|
788
|
+
});
|
|
789
|
+
if (this.isRootProject) {
|
|
790
|
+
this.buildAllTask = this.project.tasks.addTask(ROOT_CI_TASK_NAME, {
|
|
791
|
+
description: "Root build followed by sub-project builds. Mimics the CI build process in one step."
|
|
792
|
+
});
|
|
793
|
+
this.buildAllTask.exec("turbo telemetry disable");
|
|
794
|
+
if (this.buildAllTaskEnvVars) {
|
|
795
|
+
Object.entries(this.buildAllTaskEnvVars).forEach(([name, value]) => {
|
|
796
|
+
this.addGlobalEnvVar(name, value);
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
if (!this.remoteCacheOptions) {
|
|
800
|
+
this.buildAllTask.exec(
|
|
801
|
+
`turbo ${ROOT_TURBO_TASK_NAME} --summarize --concurrency=10`
|
|
802
|
+
);
|
|
803
|
+
} else {
|
|
804
|
+
this.buildAllTask.exec(
|
|
805
|
+
`turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,
|
|
806
|
+
{
|
|
807
|
+
condition: '[ ! -n "$CI" ]',
|
|
808
|
+
env: {
|
|
809
|
+
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,
|
|
810
|
+
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
);
|
|
814
|
+
this.buildAllTask.exec(
|
|
815
|
+
`turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,
|
|
816
|
+
{
|
|
817
|
+
condition: '[ -n "$CI" ]',
|
|
818
|
+
env: {
|
|
819
|
+
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text)`,
|
|
820
|
+
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text)`
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (!this.isRootProject) {
|
|
827
|
+
const generatedFiles = this.project.components.filter((c) => c instanceof FileBase).map((c) => c.path);
|
|
828
|
+
this.preCompileTask = new TurboRepoTask(project, {
|
|
829
|
+
name: options.preCompileTask?.name ?? "pre-compile",
|
|
830
|
+
inputs: ["src/**", ...generatedFiles]
|
|
831
|
+
});
|
|
832
|
+
this.compileTask = new TurboRepoTask(project, {
|
|
833
|
+
name: options.compileTask?.name ?? "compile",
|
|
834
|
+
inputs: ["src/**", ...generatedFiles]
|
|
835
|
+
});
|
|
836
|
+
this.postCompileTask = new TurboRepoTask(project, {
|
|
837
|
+
name: options.postCompileTask?.name ?? "post-compile",
|
|
838
|
+
inputs: ["src/**", ...generatedFiles]
|
|
839
|
+
});
|
|
840
|
+
this.testTask = new TurboRepoTask(project, {
|
|
841
|
+
name: options.testTask?.name ?? "test"
|
|
842
|
+
});
|
|
843
|
+
this.packageTask = new TurboRepoTask(project, {
|
|
844
|
+
name: options.packageTask?.name ?? "package",
|
|
845
|
+
inputs: [".npmignore"]
|
|
846
|
+
});
|
|
847
|
+
this.tasks.push(
|
|
848
|
+
this.preCompileTask,
|
|
849
|
+
this.compileTask,
|
|
850
|
+
this.postCompileTask,
|
|
851
|
+
this.testTask,
|
|
852
|
+
this.packageTask
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Static method to discovert turbo in a project.
|
|
858
|
+
*/
|
|
859
|
+
static of(project) {
|
|
860
|
+
const isDefined = (c) => c instanceof _TurboRepo;
|
|
861
|
+
return project.components.find(isDefined);
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Add an env var to the global env vars for all tasks.
|
|
865
|
+
* This will also become an input for the build:all task cache at the root.
|
|
866
|
+
*/
|
|
867
|
+
addGlobalEnvVar(name, value) {
|
|
868
|
+
this.buildAllTask?.env(name, value);
|
|
869
|
+
if (this.isRootProject) {
|
|
870
|
+
this.globalEnv.push(name);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Sets GIT_BRANCH_NAME so root tasks (e.g. build:all) pass the current branch.
|
|
875
|
+
* Value must be exactly $(...) so Projen's task runtime expands it; the shell
|
|
876
|
+
* then expands ${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}.
|
|
877
|
+
*/
|
|
878
|
+
activateBranchNameEnvVar() {
|
|
879
|
+
this.addGlobalEnvVar(
|
|
880
|
+
"GIT_BRANCH_NAME",
|
|
881
|
+
'$(echo "${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}")'
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
preSynthesize() {
|
|
885
|
+
let nextDependsOn = this.project.deps.all.filter((d) => d.version === "workspace:*").map((d) => [d.name, ROOT_TURBO_TASK_NAME].join("#"));
|
|
886
|
+
if (!this.isRootProject) {
|
|
887
|
+
[
|
|
888
|
+
[this.project.preCompileTask, this.preCompileTask],
|
|
889
|
+
[this.project.compileTask, this.compileTask],
|
|
890
|
+
[this.project.postCompileTask, this.postCompileTask],
|
|
891
|
+
[this.project.testTask, this.testTask],
|
|
892
|
+
[this.project.packageTask, this.packageTask]
|
|
893
|
+
].forEach(([pjTask, turboTask]) => {
|
|
894
|
+
if (pjTask && turboTask && pjTask.steps.length > 0) {
|
|
895
|
+
if (nextDependsOn.length > 0) {
|
|
896
|
+
turboTask.dependsOn.push(...nextDependsOn);
|
|
897
|
+
}
|
|
898
|
+
nextDependsOn = [turboTask.name];
|
|
899
|
+
} else {
|
|
900
|
+
turboTask.isActive = false;
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
this.buildTask.dependsOn.push(...nextDependsOn);
|
|
904
|
+
}
|
|
905
|
+
const fileName = "turbo.json";
|
|
906
|
+
this.project.addPackageIgnore(fileName);
|
|
907
|
+
new JsonFile(this.project, fileName, {
|
|
908
|
+
obj: {
|
|
909
|
+
extends: this.extends.length ? this.extends : void 0,
|
|
910
|
+
globalDependencies: this.isRootProject && this.globalDependencies.length ? this.globalDependencies : void 0,
|
|
911
|
+
globalEnv: this.isRootProject && this.globalEnv.length ? this.globalEnv : void 0,
|
|
912
|
+
globalPassThroughEnv: this.isRootProject && this.globalPassThroughEnv.length ? this.globalPassThroughEnv : void 0,
|
|
913
|
+
ui: this.isRootProject ? this.ui : void 0,
|
|
914
|
+
dangerouslyDisablePackageManagerCheck: this.isRootProject ? this.dangerouslyDisablePackageManagerCheck : void 0,
|
|
915
|
+
cacheDir: this.isRootProject ? this.cacheDir : void 0,
|
|
916
|
+
daemon: this.isRootProject ? this.daemon : void 0,
|
|
917
|
+
envMode: this.isRootProject ? this.envMode : void 0,
|
|
918
|
+
/**
|
|
919
|
+
* All tasks
|
|
920
|
+
*/
|
|
921
|
+
tasks: this.tasks.filter((task) => task.isActive).reduce(
|
|
922
|
+
(acc, task) => {
|
|
923
|
+
acc[task.name] = {
|
|
924
|
+
...task.taskConfig()
|
|
925
|
+
};
|
|
926
|
+
return acc;
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
[this.buildTask.name]: { ...this.buildTask.taskConfig() }
|
|
930
|
+
}
|
|
931
|
+
)
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
super.preSynthesize();
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
_TurboRepo.buildWorkflowOptions = (remoteCacheOptions) => {
|
|
938
|
+
return {
|
|
939
|
+
env: {
|
|
940
|
+
GIT_BRANCH_NAME: "${{ github.head_ref || github.ref_name }}"
|
|
941
|
+
},
|
|
942
|
+
permissions: {
|
|
943
|
+
contents: JobPermission.WRITE,
|
|
944
|
+
idToken: JobPermission.WRITE
|
|
945
|
+
},
|
|
946
|
+
preBuildSteps: [
|
|
947
|
+
{
|
|
948
|
+
name: "AWS Creds for SSM",
|
|
949
|
+
uses: "aws-actions/configure-aws-credentials@v4",
|
|
950
|
+
with: {
|
|
951
|
+
["role-to-assume"]: remoteCacheOptions.oidcRole,
|
|
952
|
+
["aws-region"]: "us-east-1",
|
|
953
|
+
["role-duration-seconds"]: "900"
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
]
|
|
957
|
+
};
|
|
958
|
+
};
|
|
959
|
+
var TurboRepo = _TurboRepo;
|
|
960
|
+
|
|
961
|
+
// src/agent/bundles/turborepo.ts
|
|
962
|
+
var turborepoBundle = {
|
|
963
|
+
name: "turborepo",
|
|
964
|
+
description: "Turborepo workspace rules and task pipeline conventions",
|
|
965
|
+
appliesWhen: (project) => hasComponent(project, TurboRepo),
|
|
966
|
+
rules: [
|
|
967
|
+
{
|
|
968
|
+
name: "turborepo-conventions",
|
|
969
|
+
description: "Turborepo build system and task pipeline conventions",
|
|
970
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
971
|
+
filePatterns: ["turbo.json", "package.json"],
|
|
972
|
+
content: [
|
|
973
|
+
"# Turborepo Conventions",
|
|
974
|
+
"",
|
|
975
|
+
"## Build System",
|
|
976
|
+
"",
|
|
977
|
+
"- **Build**: `pnpm build:all` (uses Turborepo)",
|
|
978
|
+
"- **Test**: `pnpm test` or `pnpm test:watch`",
|
|
979
|
+
"- **Lint**: `pnpm eslint`",
|
|
980
|
+
"",
|
|
981
|
+
"## Task Pipeline",
|
|
982
|
+
"",
|
|
983
|
+
"- Uses remote caching (requires AWS credentials)",
|
|
984
|
+
"- Only rebuilds changed packages",
|
|
985
|
+
"- Cache key based on file hashes and dependency graph",
|
|
986
|
+
"- Configured in `turbo.json`",
|
|
987
|
+
"",
|
|
988
|
+
"## Workspace Rules",
|
|
989
|
+
"",
|
|
990
|
+
"- Source files: `src/` directory",
|
|
991
|
+
"- Tests: Co-located with source files (`.spec.ts` or `.test.ts`)",
|
|
992
|
+
"- Exports: Use `index.ts` files for clean public APIs",
|
|
993
|
+
"- Configuration: Managed by Projen (edit `.projenrc.ts` or `projenrc/*.ts`)"
|
|
994
|
+
].join("\n"),
|
|
995
|
+
tags: ["workflow"]
|
|
996
|
+
}
|
|
997
|
+
]
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
// src/agent/bundles/typescript.ts
|
|
1001
|
+
var typescriptBundle = {
|
|
1002
|
+
name: "typescript",
|
|
1003
|
+
description: "TypeScript conventions, type safety, naming, JSDoc, member ordering",
|
|
1004
|
+
appliesWhen: (project) => hasFile(project, "tsconfig.json"),
|
|
1005
|
+
rules: [
|
|
1006
|
+
{
|
|
1007
|
+
name: "typescript-conventions",
|
|
1008
|
+
description: "TypeScript coding conventions and style guide",
|
|
1009
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
1010
|
+
filePatterns: ["**/*.ts", "**/*.tsx"],
|
|
1011
|
+
content: [
|
|
1012
|
+
"# TypeScript Conventions",
|
|
1013
|
+
"",
|
|
1014
|
+
"## Type Safety",
|
|
1015
|
+
"",
|
|
1016
|
+
"- Use **strict TypeScript** with all strict checks enabled",
|
|
1017
|
+
"- Always use explicit types; avoid `any` unless absolutely necessary",
|
|
1018
|
+
"- Use `readonly` for immutable properties",
|
|
1019
|
+
"- Prefer interfaces over types for object shapes",
|
|
1020
|
+
"- Use proper TypeScript types from libraries",
|
|
1021
|
+
"",
|
|
1022
|
+
"## Code Organization",
|
|
1023
|
+
"",
|
|
1024
|
+
"- Follow the member ordering rule:",
|
|
1025
|
+
" 1. Public static fields/methods",
|
|
1026
|
+
" 2. Protected static fields/methods",
|
|
1027
|
+
" 3. Private static fields/methods",
|
|
1028
|
+
" 4. Instance fields",
|
|
1029
|
+
" 5. Constructor",
|
|
1030
|
+
" 6. Methods",
|
|
1031
|
+
"",
|
|
1032
|
+
"## Documentation",
|
|
1033
|
+
"",
|
|
1034
|
+
"- **Keep JSDoc minimal** so that the code remains human-readable. Use brief summaries only.",
|
|
1035
|
+
"- Use JSDoc for:",
|
|
1036
|
+
" - Public classes and interfaces (short description)",
|
|
1037
|
+
" - Public methods and properties (brief purpose; parameter and return when not obvious)",
|
|
1038
|
+
" - Configuration options (one-line description)",
|
|
1039
|
+
"- **Extended documentation** belongs in **markdown** files. Link from JSDoc via `@see` or an inline link.",
|
|
1040
|
+
"",
|
|
1041
|
+
"## Naming Conventions",
|
|
1042
|
+
"",
|
|
1043
|
+
"- **Classes**: PascalCase (e.g., `TypeScriptProject`, `StaticHosting`)",
|
|
1044
|
+
"- **Interfaces**: PascalCase, often with `Props` suffix for configuration (e.g., `StaticHostingProps`)",
|
|
1045
|
+
"- **Functions/Methods**: camelCase (e.g., `configureProject`)",
|
|
1046
|
+
"- **Constants**: UPPER_SNAKE_CASE (e.g., `VERSION`, `AWS_STAGE_TYPE`)",
|
|
1047
|
+
"- **Files**: kebab-case for multi-word files (e.g., `aws-deployment-config.ts`)",
|
|
1048
|
+
"- **Private members**: No prefix needed (TypeScript handles visibility)"
|
|
1049
|
+
].join("\n"),
|
|
1050
|
+
tags: ["coding"]
|
|
1051
|
+
}
|
|
1052
|
+
]
|
|
1053
|
+
};
|
|
1054
|
+
|
|
1055
|
+
// src/vitest/vitest-component.ts
|
|
1056
|
+
import { Component as Component4 } from "projen";
|
|
1057
|
+
import { Jest } from "projen/lib/javascript";
|
|
1058
|
+
import { TextFile } from "projen/lib/textfile";
|
|
1059
|
+
|
|
1060
|
+
// src/versions.ts
|
|
1061
|
+
var VERSION = {
|
|
1062
|
+
/**
|
|
1063
|
+
* CDK CLI for workflows and command line operations.
|
|
1064
|
+
*
|
|
1065
|
+
* CLI and lib are versioned separately, so this is the CLI version.
|
|
1066
|
+
*/
|
|
1067
|
+
AWS_CDK_CLI_VERSION: "2.1117.0",
|
|
1068
|
+
/**
|
|
1069
|
+
* CDK Version to use for construct projects.
|
|
1070
|
+
*
|
|
1071
|
+
* CLI and lib are versioned separately, so this is the lib version.
|
|
1072
|
+
*/
|
|
1073
|
+
AWS_CDK_LIB_VERSION: "2.248.0",
|
|
1074
|
+
/**
|
|
1075
|
+
* Version of the AWS Constructs library to use.
|
|
1076
|
+
*/
|
|
1077
|
+
AWS_CONSTRUCTS_VERSION: "10.6.0",
|
|
1078
|
+
/**
|
|
1079
|
+
* Version of Node.js to use in CI workflows at github actions.
|
|
1080
|
+
*/
|
|
1081
|
+
NODE_WORKFLOWS: "24",
|
|
1082
|
+
/**
|
|
1083
|
+
* Version of PNPM to use in workflows at github actions.
|
|
1084
|
+
*/
|
|
1085
|
+
PNPM_VERSION: "10.33.0",
|
|
1086
|
+
/**
|
|
1087
|
+
* Version of Projen to use.
|
|
1088
|
+
*/
|
|
1089
|
+
PROJEN_VERSION: "0.99.34",
|
|
1090
|
+
/**
|
|
1091
|
+
* What version of the turborepo library should we use?
|
|
1092
|
+
*/
|
|
1093
|
+
TURBO_VERSION: "2.9.4",
|
|
1094
|
+
/**
|
|
1095
|
+
* What version of Vite to use (pnpm override). Pinned to 5.x so Vitest 4.x
|
|
1096
|
+
* can load config (Vite 6+/7+ are ESM-only; see issue #142). Remove override
|
|
1097
|
+
* when moving to ESM-only test setup.
|
|
1098
|
+
*/
|
|
1099
|
+
VITE_VERSION: "5.4.11",
|
|
1100
|
+
/**
|
|
1101
|
+
* What version of Vitest to use when testRunner is 'vitest'.
|
|
1102
|
+
* Pinned to 3.x so it works with Vite 5 (Vitest 4 requires Vite 6). See issue #142.
|
|
1103
|
+
*/
|
|
1104
|
+
VITEST_VERSION: "3.2.4"
|
|
1105
|
+
};
|
|
1106
|
+
|
|
1107
|
+
// src/vitest/vitest-component.ts
|
|
1108
|
+
var Vitest = class _Vitest extends Component4 {
|
|
1109
|
+
constructor(project, options = {}) {
|
|
1110
|
+
super(project);
|
|
1111
|
+
this.project = project;
|
|
1112
|
+
this.configFilePath = options.configFilePath ?? "vitest.config.ts";
|
|
1113
|
+
const config = options.config ?? {};
|
|
1114
|
+
this.include = config.include ?? ["**/*.{test,spec}.?(c|m)[jt]s?(x)"];
|
|
1115
|
+
this.exclude = config.exclude ?? [
|
|
1116
|
+
"**/node_modules/**",
|
|
1117
|
+
"**/dist/**",
|
|
1118
|
+
"**/lib/**",
|
|
1119
|
+
"**/.?*"
|
|
1120
|
+
];
|
|
1121
|
+
this.environment = config.environment ?? "node";
|
|
1122
|
+
this.passWithNoTests = config.passWithNoTests ?? true;
|
|
1123
|
+
this.coverageEnabled = config.coverageEnabled ?? true;
|
|
1124
|
+
this.coverageDirectory = config.coverageDirectory ?? "coverage";
|
|
1125
|
+
this.coverageReporters = config.coverageReporters ?? ["text", "lcov"];
|
|
1126
|
+
this.version = options.vitestVersion ?? VERSION.VITEST_VERSION;
|
|
1127
|
+
project.addDevDeps(`vitest@${this.version}`);
|
|
1128
|
+
if (this.coverageEnabled) {
|
|
1129
|
+
project.addDevDeps(`@vitest/coverage-v8@${this.version}`);
|
|
1130
|
+
}
|
|
1131
|
+
const coveragePath = `/${this.coverageDirectory}/`;
|
|
1132
|
+
project.gitignore.addPatterns(coveragePath);
|
|
1133
|
+
project.npmignore?.exclude(coveragePath);
|
|
1134
|
+
this.addTestTasks();
|
|
1135
|
+
this.synthesizeConfig();
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Find the Vitest component on a project.
|
|
1139
|
+
*/
|
|
1140
|
+
static of(project) {
|
|
1141
|
+
const isVitest = (c) => c instanceof _Vitest;
|
|
1142
|
+
return project.components.find(isVitest);
|
|
1143
|
+
}
|
|
1144
|
+
preSynthesize() {
|
|
1145
|
+
super.preSynthesize();
|
|
1146
|
+
for (const component of this.project.components) {
|
|
1147
|
+
if (component instanceof Jest) {
|
|
1148
|
+
throw new Error("Vitest cannot be used together with Jest");
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
addTestTasks() {
|
|
1153
|
+
this.project.testTask.exec("vitest run --update");
|
|
1154
|
+
if (!this.project.tasks.tryFind("test:watch")) {
|
|
1155
|
+
this.project.addTask("test:watch", {
|
|
1156
|
+
description: "Run tests in watch mode",
|
|
1157
|
+
exec: "vitest watch",
|
|
1158
|
+
receiveArgs: true
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
synthesizeConfig() {
|
|
1163
|
+
this.project.tryRemoveFile(this.configFilePath);
|
|
1164
|
+
new TextFile(this, this.configFilePath, {
|
|
1165
|
+
lines: this.renderConfig()
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
renderConfig() {
|
|
1169
|
+
return [
|
|
1170
|
+
'import { defineConfig } from "vitest/config";',
|
|
1171
|
+
"",
|
|
1172
|
+
"export default defineConfig({",
|
|
1173
|
+
" test: {",
|
|
1174
|
+
` include: ${JSON.stringify(this.include)},`,
|
|
1175
|
+
` exclude: ${JSON.stringify(this.exclude)},`,
|
|
1176
|
+
` environment: "${this.environment}",`,
|
|
1177
|
+
` passWithNoTests: ${this.passWithNoTests},`,
|
|
1178
|
+
" coverage: {",
|
|
1179
|
+
` enabled: ${this.coverageEnabled},`,
|
|
1180
|
+
` provider: "v8",`,
|
|
1181
|
+
` reportsDirectory: "${this.coverageDirectory}",`,
|
|
1182
|
+
` reporter: ${JSON.stringify(this.coverageReporters)},`,
|
|
1183
|
+
" },",
|
|
1184
|
+
" },",
|
|
1185
|
+
"});"
|
|
1186
|
+
];
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
|
|
1190
|
+
// src/agent/bundles/vitest.ts
|
|
1191
|
+
var vitestBundle = {
|
|
1192
|
+
name: "vitest",
|
|
1193
|
+
description: "Vitest testing conventions, patterns, and file scoping",
|
|
1194
|
+
appliesWhen: (project) => hasComponent(project, Vitest),
|
|
1195
|
+
rules: [
|
|
1196
|
+
{
|
|
1197
|
+
name: "vitest-testing",
|
|
1198
|
+
description: "Vitest testing conventions and patterns",
|
|
1199
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
1200
|
+
filePatterns: ["**/*.test.ts", "**/*.spec.ts"],
|
|
1201
|
+
content: [
|
|
1202
|
+
"# Vitest Testing Patterns",
|
|
1203
|
+
"",
|
|
1204
|
+
"## Mandatory Requirements",
|
|
1205
|
+
"",
|
|
1206
|
+
"- **Tests MUST be created or updated whenever code functionality is added or changed**",
|
|
1207
|
+
"- This applies to all code changes, including:",
|
|
1208
|
+
" - New features and functionality",
|
|
1209
|
+
" - Bug fixes",
|
|
1210
|
+
" - Refactoring that changes behavior",
|
|
1211
|
+
" - API changes",
|
|
1212
|
+
" - Configuration changes that affect functionality",
|
|
1213
|
+
"- Tests should be written or updated as part of the same change that modifies the code",
|
|
1214
|
+
"",
|
|
1215
|
+
"## Test Structure",
|
|
1216
|
+
"",
|
|
1217
|
+
"- Use **Vitest** as the test runner",
|
|
1218
|
+
"- Test files: `.spec.ts` or `.test.ts` (co-located with source)",
|
|
1219
|
+
"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`",
|
|
1220
|
+
"- Prefer snapshot tests for complex object structures",
|
|
1221
|
+
"- Mock external dependencies appropriately",
|
|
1222
|
+
"",
|
|
1223
|
+
"## Test Organization",
|
|
1224
|
+
"",
|
|
1225
|
+
"- Co-locate test files with source files",
|
|
1226
|
+
"- Test files can use dev dependencies (ESLint rule override)",
|
|
1227
|
+
"- Import from `vitest`: `import { describe, expect, it } from 'vitest'`",
|
|
1228
|
+
"",
|
|
1229
|
+
"## Example Test Structure",
|
|
1230
|
+
"",
|
|
1231
|
+
"```typescript",
|
|
1232
|
+
"import { describe, expect, it } from 'vitest';",
|
|
1233
|
+
"import { MyClass } from './my-class';",
|
|
1234
|
+
"",
|
|
1235
|
+
"describe('MyClass', () => {",
|
|
1236
|
+
" it('should do something specific', () => {",
|
|
1237
|
+
" // Test implementation",
|
|
1238
|
+
" });",
|
|
1239
|
+
"});",
|
|
1240
|
+
"```"
|
|
1241
|
+
].join("\n"),
|
|
1242
|
+
tags: ["testing"]
|
|
1243
|
+
}
|
|
1244
|
+
]
|
|
1245
|
+
};
|
|
1246
|
+
|
|
1247
|
+
// src/agent/bundles/index.ts
|
|
1248
|
+
var BUILT_IN_BUNDLES = [
|
|
1249
|
+
baseBundle,
|
|
1250
|
+
typescriptBundle,
|
|
1251
|
+
vitestBundle,
|
|
1252
|
+
jestBundle,
|
|
1253
|
+
turborepoBundle,
|
|
1254
|
+
pnpmBundle,
|
|
1255
|
+
awsCdkBundle,
|
|
1256
|
+
projenBundle
|
|
1257
|
+
];
|
|
1258
|
+
|
|
213
1259
|
// src/agent/renderers/claude-renderer.ts
|
|
1260
|
+
import { JsonFile as JsonFile2 } from "projen";
|
|
1261
|
+
import { TextFile as TextFile2 } from "projen/lib/textfile";
|
|
214
1262
|
var GENERATED_MARKER = "<!-- ~~ Generated by @codedrifters/configulator. Edits welcome \u2014 please contribute improvements back. ~~ -->";
|
|
215
1263
|
var ClaudeRenderer = class _ClaudeRenderer {
|
|
216
1264
|
/**
|
|
@@ -235,7 +1283,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
235
1283
|
if (i > 0) lines.push("", "---", "");
|
|
236
1284
|
lines.push(...claudeMdRules[i].content.split("\n"));
|
|
237
1285
|
}
|
|
238
|
-
new
|
|
1286
|
+
new TextFile2(component, "CLAUDE.md", { lines });
|
|
239
1287
|
}
|
|
240
1288
|
static renderScopedRules(component, rules) {
|
|
241
1289
|
const scopedRules = rules.filter((r) => {
|
|
@@ -255,7 +1303,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
255
1303
|
lines.push("");
|
|
256
1304
|
}
|
|
257
1305
|
lines.push(...rule.content.split("\n"));
|
|
258
|
-
new
|
|
1306
|
+
new TextFile2(component, `.claude/rules/${rule.name}.md`, { lines });
|
|
259
1307
|
}
|
|
260
1308
|
}
|
|
261
1309
|
static renderSettings(component, mcpServers, settings) {
|
|
@@ -370,7 +1418,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
370
1418
|
hasContent = true;
|
|
371
1419
|
}
|
|
372
1420
|
if (!hasContent) return;
|
|
373
|
-
new
|
|
1421
|
+
new JsonFile2(component, ".claude/settings.json", { obj });
|
|
374
1422
|
}
|
|
375
1423
|
static buildSandboxObj(sandbox) {
|
|
376
1424
|
const obj = {};
|
|
@@ -446,7 +1494,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
446
1494
|
lines.push("---");
|
|
447
1495
|
lines.push("");
|
|
448
1496
|
lines.push(...skill.instructions.split("\n"));
|
|
449
|
-
new
|
|
1497
|
+
new TextFile2(component, `.claude/skills/${skill.name}/SKILL.md`, {
|
|
450
1498
|
lines
|
|
451
1499
|
});
|
|
452
1500
|
}
|
|
@@ -483,7 +1531,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
483
1531
|
lines.push("---");
|
|
484
1532
|
lines.push("");
|
|
485
1533
|
lines.push(...agent.prompt.split("\n"));
|
|
486
|
-
new
|
|
1534
|
+
new TextFile2(component, `.claude/agents/${agent.name}.md`, { lines });
|
|
487
1535
|
}
|
|
488
1536
|
}
|
|
489
1537
|
/**
|
|
@@ -508,8 +1556,8 @@ var CopilotRenderer = class {
|
|
|
508
1556
|
};
|
|
509
1557
|
|
|
510
1558
|
// src/agent/renderers/cursor-renderer.ts
|
|
511
|
-
import { JsonFile as
|
|
512
|
-
import { TextFile as
|
|
1559
|
+
import { JsonFile as JsonFile3 } from "projen";
|
|
1560
|
+
import { TextFile as TextFile3 } from "projen/lib/textfile";
|
|
513
1561
|
var GENERATED_MARKER2 = "# ~~ Generated by @codedrifters/configulator. Edits welcome \u2014 please contribute improvements back. ~~";
|
|
514
1562
|
var CursorRenderer = class _CursorRenderer {
|
|
515
1563
|
/**
|
|
@@ -538,7 +1586,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
538
1586
|
lines.push("---");
|
|
539
1587
|
lines.push("");
|
|
540
1588
|
lines.push(...rule.content.split("\n"));
|
|
541
|
-
new
|
|
1589
|
+
new TextFile3(component, `.cursor/rules/${rule.name}.mdc`, { lines });
|
|
542
1590
|
}
|
|
543
1591
|
}
|
|
544
1592
|
static renderSkills(component, skills) {
|
|
@@ -562,7 +1610,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
562
1610
|
lines.push("---");
|
|
563
1611
|
lines.push("");
|
|
564
1612
|
lines.push(...skill.instructions.split("\n"));
|
|
565
|
-
new
|
|
1613
|
+
new TextFile3(component, `.cursor/skills/${skill.name}/SKILL.md`, {
|
|
566
1614
|
lines
|
|
567
1615
|
});
|
|
568
1616
|
}
|
|
@@ -587,7 +1635,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
587
1635
|
lines.push("---");
|
|
588
1636
|
lines.push("");
|
|
589
1637
|
lines.push(...agent.prompt.split("\n"));
|
|
590
|
-
new
|
|
1638
|
+
new TextFile3(component, `.cursor/agents/${agent.name}.md`, { lines });
|
|
591
1639
|
}
|
|
592
1640
|
}
|
|
593
1641
|
static renderMcpServers(component, mcpServers) {
|
|
@@ -603,7 +1651,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
603
1651
|
if (config.env) server.env = { ...config.env };
|
|
604
1652
|
servers[name] = server;
|
|
605
1653
|
}
|
|
606
|
-
new
|
|
1654
|
+
new JsonFile3(component, ".cursor/mcp.json", { obj });
|
|
607
1655
|
}
|
|
608
1656
|
static renderHooks(component, settings) {
|
|
609
1657
|
if (!settings?.hooks) return;
|
|
@@ -641,18 +1689,18 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
641
1689
|
}
|
|
642
1690
|
if (stop?.length) hooks.stop = stop.map((h) => ({ command: h.command }));
|
|
643
1691
|
if (Object.keys(hooks).length === 0) return;
|
|
644
|
-
new
|
|
1692
|
+
new JsonFile3(component, ".cursor/hooks.json", {
|
|
645
1693
|
obj: { version: 1, hooks }
|
|
646
1694
|
});
|
|
647
1695
|
}
|
|
648
1696
|
static renderIgnoreFiles(component, settings) {
|
|
649
1697
|
if (settings?.ignorePatterns && settings.ignorePatterns.length > 0) {
|
|
650
|
-
new
|
|
1698
|
+
new TextFile3(component, ".cursorignore", {
|
|
651
1699
|
lines: [GENERATED_MARKER2, "", ...settings.ignorePatterns]
|
|
652
1700
|
});
|
|
653
1701
|
}
|
|
654
1702
|
if (settings?.indexingIgnorePatterns && settings.indexingIgnorePatterns.length > 0) {
|
|
655
|
-
new
|
|
1703
|
+
new TextFile3(component, ".cursorindexingignore", {
|
|
656
1704
|
lines: [GENERATED_MARKER2, "", ...settings.indexingIgnorePatterns]
|
|
657
1705
|
});
|
|
658
1706
|
}
|
|
@@ -660,7 +1708,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
660
1708
|
};
|
|
661
1709
|
|
|
662
1710
|
// src/agent/agent-config.ts
|
|
663
|
-
var AgentConfig = class _AgentConfig extends
|
|
1711
|
+
var AgentConfig = class _AgentConfig extends Component7 {
|
|
664
1712
|
/**
|
|
665
1713
|
* Find the AgentConfig component on a project.
|
|
666
1714
|
*/
|
|
@@ -714,6 +1762,9 @@ var AgentConfig = class _AgentConfig extends Component3 {
|
|
|
714
1762
|
if (this.options.autoDetectBundles !== false) {
|
|
715
1763
|
for (const bundle of BUILT_IN_BUNDLES) {
|
|
716
1764
|
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
1765
|
+
if (bundle.name === "base" && this.options.includeBaseRules === false) {
|
|
1766
|
+
continue;
|
|
1767
|
+
}
|
|
717
1768
|
if (bundle.appliesWhen(this.project)) {
|
|
718
1769
|
for (const rule of bundle.rules) {
|
|
719
1770
|
ruleMap.set(rule.name, rule);
|
|
@@ -741,6 +1792,21 @@ var AgentConfig = class _AgentConfig extends Component3 {
|
|
|
741
1792
|
ruleMap.delete(name);
|
|
742
1793
|
}
|
|
743
1794
|
}
|
|
1795
|
+
if (this.options.ruleExtensions) {
|
|
1796
|
+
for (const [name, extra] of Object.entries(this.options.ruleExtensions)) {
|
|
1797
|
+
const existing = ruleMap.get(name);
|
|
1798
|
+
if (existing) {
|
|
1799
|
+
ruleMap.set(name, {
|
|
1800
|
+
...existing,
|
|
1801
|
+
content: `${existing.content}
|
|
1802
|
+
|
|
1803
|
+
---
|
|
1804
|
+
|
|
1805
|
+
${extra}`
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
744
1810
|
return [...ruleMap.values()].sort((a, b) => {
|
|
745
1811
|
if (a.name === "project-overview") return -1;
|
|
746
1812
|
if (b.name === "project-overview") return 1;
|
|
@@ -761,291 +1827,40 @@ var AgentConfig = class _AgentConfig extends Component3 {
|
|
|
761
1827
|
}
|
|
762
1828
|
}
|
|
763
1829
|
}
|
|
764
|
-
}
|
|
765
|
-
if (this.options.skills) {
|
|
766
|
-
for (const skill of this.options.skills) {
|
|
767
|
-
skillMap.set(skill.name, skill);
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
return [...skillMap.values()];
|
|
771
|
-
}
|
|
772
|
-
resolveSubAgents() {
|
|
773
|
-
const agentMap = /* @__PURE__ */ new Map();
|
|
774
|
-
if (this.options.autoDetectBundles !== false) {
|
|
775
|
-
for (const bundle of BUILT_IN_BUNDLES) {
|
|
776
|
-
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
777
|
-
if (bundle.appliesWhen(this.project) && bundle.subAgents) {
|
|
778
|
-
for (const agent of bundle.subAgents) {
|
|
779
|
-
agentMap.set(agent.name, agent);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
if (this.options.subAgents) {
|
|
785
|
-
for (const agent of this.options.subAgents) {
|
|
786
|
-
agentMap.set(agent.name, agent);
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
return [...agentMap.values()];
|
|
790
|
-
}
|
|
791
|
-
};
|
|
792
|
-
|
|
793
|
-
// src/aws/aws-deployment-config.ts
|
|
794
|
-
var import_utils = __toESM(require_lib());
|
|
795
|
-
import { join, relative } from "path";
|
|
796
|
-
import { Component as Component6 } from "projen";
|
|
797
|
-
|
|
798
|
-
// src/turbo/turbo-repo-task.ts
|
|
799
|
-
import { Component as Component4 } from "projen/lib";
|
|
800
|
-
var TurboRepoTask = class extends Component4 {
|
|
801
|
-
constructor(project, options) {
|
|
802
|
-
super(project);
|
|
803
|
-
this.project = project;
|
|
804
|
-
this.name = options.name;
|
|
805
|
-
this.dependsOn = options.dependsOn ?? [];
|
|
806
|
-
this.env = options.env ?? [];
|
|
807
|
-
this.passThroughEnv = options.passThroughEnv ?? [];
|
|
808
|
-
this.outputs = options.outputs ?? [];
|
|
809
|
-
this.cache = options.cache ?? true;
|
|
810
|
-
this.inputs = [
|
|
811
|
-
...options.inputs ?? [],
|
|
812
|
-
// rerun if projen config changes
|
|
813
|
-
".projen/**",
|
|
814
|
-
// ignore mac files
|
|
815
|
-
"!.DS_Store",
|
|
816
|
-
"!**/.DS_Store"
|
|
817
|
-
];
|
|
818
|
-
this.outputLogs = options.outputLogs ?? "new-only";
|
|
819
|
-
this.persistent = options.persistent ?? false;
|
|
820
|
-
this.interactive = options.interactive ?? false;
|
|
821
|
-
this.isActive = true;
|
|
822
|
-
}
|
|
823
|
-
taskConfig() {
|
|
824
|
-
return {
|
|
825
|
-
dependsOn: this.dependsOn,
|
|
826
|
-
env: this.env,
|
|
827
|
-
passThroughEnv: this.passThroughEnv,
|
|
828
|
-
outputs: this.outputs,
|
|
829
|
-
cache: this.cache,
|
|
830
|
-
inputs: this.inputs,
|
|
831
|
-
outputLogs: this.outputLogs,
|
|
832
|
-
persistent: this.persistent,
|
|
833
|
-
interactive: this.interactive
|
|
834
|
-
};
|
|
835
|
-
}
|
|
836
|
-
};
|
|
837
|
-
|
|
838
|
-
// src/turbo/turbo-repo.ts
|
|
839
|
-
import { Component as Component5, FileBase, JsonFile as JsonFile3 } from "projen/lib";
|
|
840
|
-
import { JobPermission } from "projen/lib/github/workflows-model";
|
|
841
|
-
var ROOT_TURBO_TASK_NAME = "turbo:build";
|
|
842
|
-
var ROOT_CI_TASK_NAME = "build:all";
|
|
843
|
-
var _TurboRepo = class _TurboRepo extends Component5 {
|
|
844
|
-
constructor(project, options = {}) {
|
|
845
|
-
super(project);
|
|
846
|
-
this.project = project;
|
|
847
|
-
/**
|
|
848
|
-
* Sub-Tasks to run
|
|
849
|
-
*/
|
|
850
|
-
this.tasks = [];
|
|
851
|
-
this.turboVersion = options.turboVersion ?? "catalog:";
|
|
852
|
-
this.isRootProject = project === project.root;
|
|
853
|
-
if (this.isRootProject) {
|
|
854
|
-
project.addDevDeps(`turbo@${this.turboVersion}`);
|
|
855
|
-
}
|
|
856
|
-
project.gitignore.addPatterns("/.turbo");
|
|
857
|
-
project.npmignore?.addPatterns("/.turbo/");
|
|
858
|
-
this.extends = options.extends ?? (this.isRootProject ? [] : ["//"]);
|
|
859
|
-
this.globalDependencies = options.globalDependencies ?? [];
|
|
860
|
-
this.globalEnv = options.globalEnv ?? [];
|
|
861
|
-
this.globalPassThroughEnv = options.globalPassThroughEnv ?? [];
|
|
862
|
-
this.ui = options.ui ?? "stream";
|
|
863
|
-
this.dangerouslyDisablePackageManagerCheck = options.dangerouslyDisablePackageManagerCheck ?? false;
|
|
864
|
-
this.cacheDir = options.cacheDir ?? ".turbo/cache";
|
|
865
|
-
this.daemon = options.daemon ?? true;
|
|
866
|
-
this.envMode = options.envMode ?? "strict";
|
|
867
|
-
this.remoteCacheOptions = options.remoteCacheOptions;
|
|
868
|
-
this.buildAllTaskEnvVars = options.buildAllTaskEnvVars ?? {};
|
|
869
|
-
const rootGeneratedFiles = this.isRootProject ? this.project.components.filter((c) => c instanceof FileBase).map((c) => c.path) : [];
|
|
870
|
-
this.buildTask = new TurboRepoTask(this.project, {
|
|
871
|
-
name: ROOT_TURBO_TASK_NAME,
|
|
872
|
-
dependsOn: this.isRootProject ? [`^${ROOT_TURBO_TASK_NAME}`] : [],
|
|
873
|
-
...rootGeneratedFiles.length > 0 && { inputs: rootGeneratedFiles }
|
|
874
|
-
});
|
|
875
|
-
if (this.isRootProject) {
|
|
876
|
-
this.buildAllTask = this.project.tasks.addTask(ROOT_CI_TASK_NAME, {
|
|
877
|
-
description: "Root build followed by sub-project builds. Mimics the CI build process in one step."
|
|
878
|
-
});
|
|
879
|
-
this.buildAllTask.exec("turbo telemetry disable");
|
|
880
|
-
if (this.buildAllTaskEnvVars) {
|
|
881
|
-
Object.entries(this.buildAllTaskEnvVars).forEach(([name, value]) => {
|
|
882
|
-
this.addGlobalEnvVar(name, value);
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
if (!this.remoteCacheOptions) {
|
|
886
|
-
this.buildAllTask.exec(
|
|
887
|
-
`turbo ${ROOT_TURBO_TASK_NAME} --summarize --concurrency=10`
|
|
888
|
-
);
|
|
889
|
-
} else {
|
|
890
|
-
this.buildAllTask.exec(
|
|
891
|
-
`turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,
|
|
892
|
-
{
|
|
893
|
-
condition: '[ ! -n "$CI" ]',
|
|
894
|
-
env: {
|
|
895
|
-
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,
|
|
896
|
-
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
);
|
|
900
|
-
this.buildAllTask.exec(
|
|
901
|
-
`turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,
|
|
902
|
-
{
|
|
903
|
-
condition: '[ -n "$CI" ]',
|
|
904
|
-
env: {
|
|
905
|
-
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text)`,
|
|
906
|
-
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text)`
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
);
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
if (!this.isRootProject) {
|
|
913
|
-
const generatedFiles = this.project.components.filter((c) => c instanceof FileBase).map((c) => c.path);
|
|
914
|
-
this.preCompileTask = new TurboRepoTask(project, {
|
|
915
|
-
name: options.preCompileTask?.name ?? "pre-compile",
|
|
916
|
-
inputs: ["src/**", ...generatedFiles]
|
|
917
|
-
});
|
|
918
|
-
this.compileTask = new TurboRepoTask(project, {
|
|
919
|
-
name: options.compileTask?.name ?? "compile",
|
|
920
|
-
inputs: ["src/**", ...generatedFiles]
|
|
921
|
-
});
|
|
922
|
-
this.postCompileTask = new TurboRepoTask(project, {
|
|
923
|
-
name: options.postCompileTask?.name ?? "post-compile",
|
|
924
|
-
inputs: ["src/**", ...generatedFiles]
|
|
925
|
-
});
|
|
926
|
-
this.testTask = new TurboRepoTask(project, {
|
|
927
|
-
name: options.testTask?.name ?? "test"
|
|
928
|
-
});
|
|
929
|
-
this.packageTask = new TurboRepoTask(project, {
|
|
930
|
-
name: options.packageTask?.name ?? "package",
|
|
931
|
-
inputs: [".npmignore"]
|
|
932
|
-
});
|
|
933
|
-
this.tasks.push(
|
|
934
|
-
this.preCompileTask,
|
|
935
|
-
this.compileTask,
|
|
936
|
-
this.postCompileTask,
|
|
937
|
-
this.testTask,
|
|
938
|
-
this.packageTask
|
|
939
|
-
);
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
/**
|
|
943
|
-
* Static method to discovert turbo in a project.
|
|
944
|
-
*/
|
|
945
|
-
static of(project) {
|
|
946
|
-
const isDefined = (c) => c instanceof _TurboRepo;
|
|
947
|
-
return project.components.find(isDefined);
|
|
948
|
-
}
|
|
949
|
-
/**
|
|
950
|
-
* Add an env var to the global env vars for all tasks.
|
|
951
|
-
* This will also become an input for the build:all task cache at the root.
|
|
952
|
-
*/
|
|
953
|
-
addGlobalEnvVar(name, value) {
|
|
954
|
-
this.buildAllTask?.env(name, value);
|
|
955
|
-
if (this.isRootProject) {
|
|
956
|
-
this.globalEnv.push(name);
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
/**
|
|
960
|
-
* Sets GIT_BRANCH_NAME so root tasks (e.g. build:all) pass the current branch.
|
|
961
|
-
* Value must be exactly $(...) so Projen's task runtime expands it; the shell
|
|
962
|
-
* then expands ${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}.
|
|
963
|
-
*/
|
|
964
|
-
activateBranchNameEnvVar() {
|
|
965
|
-
this.addGlobalEnvVar(
|
|
966
|
-
"GIT_BRANCH_NAME",
|
|
967
|
-
'$(echo "${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}")'
|
|
968
|
-
);
|
|
969
|
-
}
|
|
970
|
-
preSynthesize() {
|
|
971
|
-
let nextDependsOn = this.project.deps.all.filter((d) => d.version === "workspace:*").map((d) => [d.name, ROOT_TURBO_TASK_NAME].join("#"));
|
|
972
|
-
if (!this.isRootProject) {
|
|
973
|
-
[
|
|
974
|
-
[this.project.preCompileTask, this.preCompileTask],
|
|
975
|
-
[this.project.compileTask, this.compileTask],
|
|
976
|
-
[this.project.postCompileTask, this.postCompileTask],
|
|
977
|
-
[this.project.testTask, this.testTask],
|
|
978
|
-
[this.project.packageTask, this.packageTask]
|
|
979
|
-
].forEach(([pjTask, turboTask]) => {
|
|
980
|
-
if (pjTask && turboTask && pjTask.steps.length > 0) {
|
|
981
|
-
if (nextDependsOn.length > 0) {
|
|
982
|
-
turboTask.dependsOn.push(...nextDependsOn);
|
|
983
|
-
}
|
|
984
|
-
nextDependsOn = [turboTask.name];
|
|
985
|
-
} else {
|
|
986
|
-
turboTask.isActive = false;
|
|
987
|
-
}
|
|
988
|
-
});
|
|
989
|
-
this.buildTask.dependsOn.push(...nextDependsOn);
|
|
990
|
-
}
|
|
991
|
-
const fileName = "turbo.json";
|
|
992
|
-
this.project.addPackageIgnore(fileName);
|
|
993
|
-
new JsonFile3(this.project, fileName, {
|
|
994
|
-
obj: {
|
|
995
|
-
extends: this.extends.length ? this.extends : void 0,
|
|
996
|
-
globalDependencies: this.isRootProject && this.globalDependencies.length ? this.globalDependencies : void 0,
|
|
997
|
-
globalEnv: this.isRootProject && this.globalEnv.length ? this.globalEnv : void 0,
|
|
998
|
-
globalPassThroughEnv: this.isRootProject && this.globalPassThroughEnv.length ? this.globalPassThroughEnv : void 0,
|
|
999
|
-
ui: this.isRootProject ? this.ui : void 0,
|
|
1000
|
-
dangerouslyDisablePackageManagerCheck: this.isRootProject ? this.dangerouslyDisablePackageManagerCheck : void 0,
|
|
1001
|
-
cacheDir: this.isRootProject ? this.cacheDir : void 0,
|
|
1002
|
-
daemon: this.isRootProject ? this.daemon : void 0,
|
|
1003
|
-
envMode: this.isRootProject ? this.envMode : void 0,
|
|
1004
|
-
/**
|
|
1005
|
-
* All tasks
|
|
1006
|
-
*/
|
|
1007
|
-
tasks: this.tasks.filter((task) => task.isActive).reduce(
|
|
1008
|
-
(acc, task) => {
|
|
1009
|
-
acc[task.name] = {
|
|
1010
|
-
...task.taskConfig()
|
|
1011
|
-
};
|
|
1012
|
-
return acc;
|
|
1013
|
-
},
|
|
1014
|
-
{
|
|
1015
|
-
[this.buildTask.name]: { ...this.buildTask.taskConfig() }
|
|
1016
|
-
}
|
|
1017
|
-
)
|
|
1830
|
+
}
|
|
1831
|
+
if (this.options.skills) {
|
|
1832
|
+
for (const skill of this.options.skills) {
|
|
1833
|
+
skillMap.set(skill.name, skill);
|
|
1018
1834
|
}
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1835
|
+
}
|
|
1836
|
+
return [...skillMap.values()];
|
|
1021
1837
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
},
|
|
1032
|
-
preBuildSteps: [
|
|
1033
|
-
{
|
|
1034
|
-
name: "AWS Creds for SSM",
|
|
1035
|
-
uses: "aws-actions/configure-aws-credentials@v4",
|
|
1036
|
-
with: {
|
|
1037
|
-
["role-to-assume"]: remoteCacheOptions.oidcRole,
|
|
1038
|
-
["aws-region"]: "us-east-1",
|
|
1039
|
-
["role-duration-seconds"]: "900"
|
|
1838
|
+
resolveSubAgents() {
|
|
1839
|
+
const agentMap = /* @__PURE__ */ new Map();
|
|
1840
|
+
if (this.options.autoDetectBundles !== false) {
|
|
1841
|
+
for (const bundle of BUILT_IN_BUNDLES) {
|
|
1842
|
+
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
1843
|
+
if (bundle.appliesWhen(this.project) && bundle.subAgents) {
|
|
1844
|
+
for (const agent of bundle.subAgents) {
|
|
1845
|
+
agentMap.set(agent.name, agent);
|
|
1846
|
+
}
|
|
1040
1847
|
}
|
|
1041
1848
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
1849
|
+
}
|
|
1850
|
+
if (this.options.subAgents) {
|
|
1851
|
+
for (const agent of this.options.subAgents) {
|
|
1852
|
+
agentMap.set(agent.name, agent);
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
return [...agentMap.values()];
|
|
1856
|
+
}
|
|
1044
1857
|
};
|
|
1045
|
-
var TurboRepo = _TurboRepo;
|
|
1046
1858
|
|
|
1047
1859
|
// src/aws/aws-deployment-config.ts
|
|
1048
|
-
var
|
|
1860
|
+
var import_utils8 = __toESM(require_lib());
|
|
1861
|
+
import { join, relative as relative2 } from "path";
|
|
1862
|
+
import { Component as Component8 } from "projen";
|
|
1863
|
+
var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component8 {
|
|
1049
1864
|
constructor(project) {
|
|
1050
1865
|
super(project);
|
|
1051
1866
|
/**
|
|
@@ -1069,8 +1884,8 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component6 {
|
|
|
1069
1884
|
this.env = {
|
|
1070
1885
|
GIT_BRANCH_NAME: '$(echo "${GIT_BRANCH_NAME:-$(git branch --show-current)}")'
|
|
1071
1886
|
};
|
|
1072
|
-
this.projectPath =
|
|
1073
|
-
this.rootPath =
|
|
1887
|
+
this.projectPath = relative2(project.root.outdir, project.outdir);
|
|
1888
|
+
this.rootPath = relative2(project.outdir, project.root.outdir);
|
|
1074
1889
|
this.rootCdkOut = join("dist", this.projectPath, "cdk.out");
|
|
1075
1890
|
this.cdkOut = join(this.rootPath, "dist", this.projectPath, "cdk.out");
|
|
1076
1891
|
["deploy", "watch"].forEach((taskName) => {
|
|
@@ -1100,17 +1915,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component6 {
|
|
|
1100
1915
|
*/
|
|
1101
1916
|
get prodTargets() {
|
|
1102
1917
|
return this.awsDeploymentTargets.filter(
|
|
1103
|
-
(target) => target.awsStageType ===
|
|
1918
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD
|
|
1104
1919
|
);
|
|
1105
1920
|
}
|
|
1106
1921
|
get prodTargetsForCI() {
|
|
1107
1922
|
return this.awsDeploymentTargets.filter(
|
|
1108
|
-
(target) => target.awsStageType ===
|
|
1923
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD && target.ciDeployment
|
|
1109
1924
|
);
|
|
1110
1925
|
}
|
|
1111
1926
|
get prodTargetsForLocal() {
|
|
1112
1927
|
return this.awsDeploymentTargets.filter(
|
|
1113
|
-
(target) => target.awsStageType ===
|
|
1928
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD && target.localDeployment
|
|
1114
1929
|
);
|
|
1115
1930
|
}
|
|
1116
1931
|
/**
|
|
@@ -1119,17 +1934,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component6 {
|
|
|
1119
1934
|
*/
|
|
1120
1935
|
get stageTargets() {
|
|
1121
1936
|
return this.awsDeploymentTargets.filter(
|
|
1122
|
-
(target) => target.awsStageType ===
|
|
1937
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE
|
|
1123
1938
|
);
|
|
1124
1939
|
}
|
|
1125
1940
|
get stageTargetsForCI() {
|
|
1126
1941
|
return this.awsDeploymentTargets.filter(
|
|
1127
|
-
(target) => target.awsStageType ===
|
|
1942
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE && target.ciDeployment
|
|
1128
1943
|
);
|
|
1129
1944
|
}
|
|
1130
1945
|
get stageTargetsForLocal() {
|
|
1131
1946
|
return this.awsDeploymentTargets.filter(
|
|
1132
|
-
(target) => target.awsStageType ===
|
|
1947
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE && target.localDeployment
|
|
1133
1948
|
);
|
|
1134
1949
|
}
|
|
1135
1950
|
/**
|
|
@@ -1138,17 +1953,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component6 {
|
|
|
1138
1953
|
*/
|
|
1139
1954
|
get devTargets() {
|
|
1140
1955
|
return this.awsDeploymentTargets.filter(
|
|
1141
|
-
(target) => target.awsStageType ===
|
|
1956
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV
|
|
1142
1957
|
);
|
|
1143
1958
|
}
|
|
1144
1959
|
get devTargetsForCI() {
|
|
1145
1960
|
return this.awsDeploymentTargets.filter(
|
|
1146
|
-
(target) => target.awsStageType ===
|
|
1961
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV && target.ciDeployment
|
|
1147
1962
|
);
|
|
1148
1963
|
}
|
|
1149
1964
|
get devTargetsForLocal() {
|
|
1150
1965
|
return this.awsDeploymentTargets.filter(
|
|
1151
|
-
(target) => target.awsStageType ===
|
|
1966
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV && target.localDeployment
|
|
1152
1967
|
);
|
|
1153
1968
|
}
|
|
1154
1969
|
preSynthesize() {
|
|
@@ -1161,9 +1976,9 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component6 {
|
|
|
1161
1976
|
};
|
|
1162
1977
|
|
|
1163
1978
|
// src/aws/aws-deployment-target.ts
|
|
1164
|
-
var
|
|
1165
|
-
import { Component as
|
|
1166
|
-
var AwsDeploymentTarget = class _AwsDeploymentTarget extends
|
|
1979
|
+
var import_utils9 = __toESM(require_lib());
|
|
1980
|
+
import { Component as Component9 } from "projen";
|
|
1981
|
+
var AwsDeploymentTarget = class _AwsDeploymentTarget extends Component9 {
|
|
1167
1982
|
constructor(project, options) {
|
|
1168
1983
|
super(project);
|
|
1169
1984
|
/**
|
|
@@ -1228,11 +2043,11 @@ var AwsDeploymentTarget = class _AwsDeploymentTarget extends Component7 {
|
|
|
1228
2043
|
};
|
|
1229
2044
|
this.account = options.account;
|
|
1230
2045
|
this.region = options.region;
|
|
1231
|
-
this.awsStageType = options.awsStageType ||
|
|
1232
|
-
const role = options.deploymentTargetRole ?? options.awsEnvironmentType ??
|
|
2046
|
+
this.awsStageType = options.awsStageType || import_utils9.AWS_STAGE_TYPE.DEV;
|
|
2047
|
+
const role = options.deploymentTargetRole ?? options.awsEnvironmentType ?? import_utils9.DEPLOYMENT_TARGET_ROLE.PRIMARY;
|
|
1233
2048
|
this.deploymentTargetRole = role;
|
|
1234
2049
|
this.awsEnvironmentType = role;
|
|
1235
|
-
this.branches = options.branches ?? (this.awsStageType ===
|
|
2050
|
+
this.branches = options.branches ?? (this.awsStageType === import_utils9.AWS_STAGE_TYPE.PROD ? [
|
|
1236
2051
|
{
|
|
1237
2052
|
branch: "main"
|
|
1238
2053
|
}
|
|
@@ -1241,7 +2056,7 @@ var AwsDeploymentTarget = class _AwsDeploymentTarget extends Component7 {
|
|
|
1241
2056
|
branch: "feature/*"
|
|
1242
2057
|
}
|
|
1243
2058
|
]);
|
|
1244
|
-
this.localDeployment = options.localDeployment ?? this.awsStageType ===
|
|
2059
|
+
this.localDeployment = options.localDeployment ?? this.awsStageType === import_utils9.AWS_STAGE_TYPE.DEV;
|
|
1245
2060
|
if (this.localDeployment) {
|
|
1246
2061
|
const roleName = options.localDeploymentConfig?.roleName?.toLowerCase() || "poweruseraccess";
|
|
1247
2062
|
const profile = options.localDeploymentConfig?.profile || `${roleName}-${this.awsStageType}-${this.account}-${this.region}`;
|
|
@@ -1376,61 +2191,14 @@ var VERSION_KEYS_SKIP = [
|
|
|
1376
2191
|
// Pinned to 3.x for Vite 5 compatibility; skip until ESM-only (issue #142)
|
|
1377
2192
|
];
|
|
1378
2193
|
|
|
1379
|
-
// src/versions.ts
|
|
1380
|
-
var VERSION = {
|
|
1381
|
-
/**
|
|
1382
|
-
* CDK CLI for workflows and command line operations.
|
|
1383
|
-
*
|
|
1384
|
-
* CLI and lib are versioned separately, so this is the CLI version.
|
|
1385
|
-
*/
|
|
1386
|
-
AWS_CDK_CLI_VERSION: "2.1117.0",
|
|
1387
|
-
/**
|
|
1388
|
-
* CDK Version to use for construct projects.
|
|
1389
|
-
*
|
|
1390
|
-
* CLI and lib are versioned separately, so this is the lib version.
|
|
1391
|
-
*/
|
|
1392
|
-
AWS_CDK_LIB_VERSION: "2.248.0",
|
|
1393
|
-
/**
|
|
1394
|
-
* Version of the AWS Constructs library to use.
|
|
1395
|
-
*/
|
|
1396
|
-
AWS_CONSTRUCTS_VERSION: "10.6.0",
|
|
1397
|
-
/**
|
|
1398
|
-
* Version of Node.js to use in CI workflows at github actions.
|
|
1399
|
-
*/
|
|
1400
|
-
NODE_WORKFLOWS: "24",
|
|
1401
|
-
/**
|
|
1402
|
-
* Version of PNPM to use in workflows at github actions.
|
|
1403
|
-
*/
|
|
1404
|
-
PNPM_VERSION: "10.33.0",
|
|
1405
|
-
/**
|
|
1406
|
-
* Version of Projen to use.
|
|
1407
|
-
*/
|
|
1408
|
-
PROJEN_VERSION: "0.99.34",
|
|
1409
|
-
/**
|
|
1410
|
-
* What version of the turborepo library should we use?
|
|
1411
|
-
*/
|
|
1412
|
-
TURBO_VERSION: "2.9.4",
|
|
1413
|
-
/**
|
|
1414
|
-
* What version of Vite to use (pnpm override). Pinned to 5.x so Vitest 4.x
|
|
1415
|
-
* can load config (Vite 6+/7+ are ESM-only; see issue #142). Remove override
|
|
1416
|
-
* when moving to ESM-only test setup.
|
|
1417
|
-
*/
|
|
1418
|
-
VITE_VERSION: "5.4.11",
|
|
1419
|
-
/**
|
|
1420
|
-
* What version of Vitest to use when testRunner is 'vitest'.
|
|
1421
|
-
* Pinned to 3.x so it works with Vite 5 (Vitest 4 requires Vite 6). See issue #142.
|
|
1422
|
-
*/
|
|
1423
|
-
VITEST_VERSION: "3.2.4"
|
|
1424
|
-
};
|
|
1425
|
-
|
|
1426
2194
|
// src/jsii/jsii-faker.ts
|
|
1427
2195
|
import * as spec from "@jsii/spec";
|
|
1428
|
-
import { Component as
|
|
2196
|
+
import { Component as Component10, JsonFile as JsonFile4 } from "projen";
|
|
1429
2197
|
var ProjenBaseFqn = {
|
|
1430
2198
|
TYPESCRIPT_PROJECT: "projen.typescript.TypeScriptProject",
|
|
1431
2199
|
TYPESCRIPT_PROJECT_OPTIONS: "projen.typescript.TypeScriptProjectOptions"
|
|
1432
2200
|
};
|
|
1433
|
-
var JsiiFaker = class _JsiiFaker extends
|
|
2201
|
+
var JsiiFaker = class _JsiiFaker extends Component10 {
|
|
1434
2202
|
constructor(project) {
|
|
1435
2203
|
super(project);
|
|
1436
2204
|
this.project = project;
|
|
@@ -1478,86 +2246,6 @@ var JsiiFaker = class _JsiiFaker extends Component8 {
|
|
|
1478
2246
|
}
|
|
1479
2247
|
};
|
|
1480
2248
|
|
|
1481
|
-
// src/pnpm/pnpm-workspace.ts
|
|
1482
|
-
import { relative as relative2 } from "path";
|
|
1483
|
-
import { Component as Component9, YamlFile } from "projen";
|
|
1484
|
-
var MIMIMUM_RELEASE_AGE = {
|
|
1485
|
-
ZERO_DAYS: 0,
|
|
1486
|
-
ONE_HOUR: 60,
|
|
1487
|
-
SIX_HOURS: 360,
|
|
1488
|
-
TWELVE_HOURS: 720,
|
|
1489
|
-
ONE_DAY: 1440,
|
|
1490
|
-
TWO_DAYS: 2880,
|
|
1491
|
-
THREE_DAYS: 4320,
|
|
1492
|
-
FOUR_DAYS: 5760,
|
|
1493
|
-
FIVE_DAYS: 7200,
|
|
1494
|
-
SIX_DAYS: 8640,
|
|
1495
|
-
ONE_WEEK: 10080
|
|
1496
|
-
};
|
|
1497
|
-
var PnpmWorkspace = class _PnpmWorkspace extends Component9 {
|
|
1498
|
-
/**
|
|
1499
|
-
* Get the pnpm workspace component of a project. If it does not exist,
|
|
1500
|
-
* return undefined.
|
|
1501
|
-
*
|
|
1502
|
-
* @param project
|
|
1503
|
-
* @returns
|
|
1504
|
-
*/
|
|
1505
|
-
static of(project) {
|
|
1506
|
-
const isDefined = (c) => c instanceof _PnpmWorkspace;
|
|
1507
|
-
return project.root.components.find(isDefined);
|
|
1508
|
-
}
|
|
1509
|
-
constructor(project, options = {}) {
|
|
1510
|
-
super(project);
|
|
1511
|
-
project.tryFindObjectFile("package.json")?.addDeletionOverride("pnpm");
|
|
1512
|
-
this.fileName = options.fileName ?? "pnpm-workspace.yaml";
|
|
1513
|
-
this.minimumReleaseAge = options.minimumReleaseAge ?? MIMIMUM_RELEASE_AGE.ONE_DAY;
|
|
1514
|
-
this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude ? ["@codedrifters/*", ...options.minimumReleaseAgeExclude] : ["@codedrifters/*"];
|
|
1515
|
-
this.onlyBuiltDependencies = options.onlyBuiltDependencies ? options.onlyBuiltDependencies : [];
|
|
1516
|
-
this.ignoredBuiltDependencies = options.ignoredBuiltDependencies ? options.ignoredBuiltDependencies : [];
|
|
1517
|
-
this.subprojects = options.subprojects ?? [];
|
|
1518
|
-
this.defaultCatalog = options.defaultCatalog;
|
|
1519
|
-
this.namedCatalogs = options.namedCatalogs;
|
|
1520
|
-
project.addPackageIgnore(this.fileName);
|
|
1521
|
-
new YamlFile(this.project, this.fileName, {
|
|
1522
|
-
obj: () => {
|
|
1523
|
-
const pnpmConfig = {};
|
|
1524
|
-
const packages = new Array();
|
|
1525
|
-
for (const subproject of project.subprojects) {
|
|
1526
|
-
packages.push(relative2(this.project.outdir, subproject.outdir));
|
|
1527
|
-
}
|
|
1528
|
-
const packageSet = new Set(packages);
|
|
1529
|
-
for (const subprojectPath of this.subprojects) {
|
|
1530
|
-
packageSet.add(subprojectPath);
|
|
1531
|
-
}
|
|
1532
|
-
if (this.subprojects.length > 0) {
|
|
1533
|
-
packages.length = 0;
|
|
1534
|
-
packages.push(...packageSet);
|
|
1535
|
-
}
|
|
1536
|
-
pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;
|
|
1537
|
-
if (this.minimumReleaseAgeExclude.length > 0) {
|
|
1538
|
-
pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;
|
|
1539
|
-
}
|
|
1540
|
-
if (this.onlyBuiltDependencies.length > 0) {
|
|
1541
|
-
pnpmConfig.onlyBuiltDependencies = this.onlyBuiltDependencies;
|
|
1542
|
-
}
|
|
1543
|
-
if (this.ignoredBuiltDependencies.length > 0) {
|
|
1544
|
-
pnpmConfig.ignoreBuiltDependencies = this.ignoredBuiltDependencies;
|
|
1545
|
-
}
|
|
1546
|
-
if (this.defaultCatalog && Object.keys(this.defaultCatalog).length > 0) {
|
|
1547
|
-
pnpmConfig.catalog = this.defaultCatalog;
|
|
1548
|
-
}
|
|
1549
|
-
if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {
|
|
1550
|
-
pnpmConfig.namedCatalogs = this.namedCatalogs;
|
|
1551
|
-
}
|
|
1552
|
-
return {
|
|
1553
|
-
...packages.length > 0 ? { packages } : {},
|
|
1554
|
-
...pnpmConfig ? { ...pnpmConfig } : {}
|
|
1555
|
-
};
|
|
1556
|
-
}
|
|
1557
|
-
});
|
|
1558
|
-
}
|
|
1559
|
-
};
|
|
1560
|
-
|
|
1561
2249
|
// src/projects/monorepo-project.ts
|
|
1562
2250
|
import {
|
|
1563
2251
|
NodePackageManager as NodePackageManager2,
|
|
@@ -1580,94 +2268,6 @@ import {
|
|
|
1580
2268
|
} from "projen/lib/javascript";
|
|
1581
2269
|
import { ReleaseTrigger } from "projen/lib/release";
|
|
1582
2270
|
import { merge } from "ts-deepmerge";
|
|
1583
|
-
|
|
1584
|
-
// src/vitest/vitest-component.ts
|
|
1585
|
-
import { Component as Component10 } from "projen";
|
|
1586
|
-
import { Jest } from "projen/lib/javascript";
|
|
1587
|
-
import { TextFile as TextFile3 } from "projen/lib/textfile";
|
|
1588
|
-
var Vitest = class _Vitest extends Component10 {
|
|
1589
|
-
constructor(project, options = {}) {
|
|
1590
|
-
super(project);
|
|
1591
|
-
this.project = project;
|
|
1592
|
-
this.configFilePath = options.configFilePath ?? "vitest.config.ts";
|
|
1593
|
-
const config = options.config ?? {};
|
|
1594
|
-
this.include = config.include ?? ["**/*.{test,spec}.?(c|m)[jt]s?(x)"];
|
|
1595
|
-
this.exclude = config.exclude ?? [
|
|
1596
|
-
"**/node_modules/**",
|
|
1597
|
-
"**/dist/**",
|
|
1598
|
-
"**/lib/**",
|
|
1599
|
-
"**/.?*"
|
|
1600
|
-
];
|
|
1601
|
-
this.environment = config.environment ?? "node";
|
|
1602
|
-
this.passWithNoTests = config.passWithNoTests ?? true;
|
|
1603
|
-
this.coverageEnabled = config.coverageEnabled ?? true;
|
|
1604
|
-
this.coverageDirectory = config.coverageDirectory ?? "coverage";
|
|
1605
|
-
this.coverageReporters = config.coverageReporters ?? ["text", "lcov"];
|
|
1606
|
-
this.version = options.vitestVersion ?? VERSION.VITEST_VERSION;
|
|
1607
|
-
project.addDevDeps(`vitest@${this.version}`);
|
|
1608
|
-
if (this.coverageEnabled) {
|
|
1609
|
-
project.addDevDeps(`@vitest/coverage-v8@${this.version}`);
|
|
1610
|
-
}
|
|
1611
|
-
const coveragePath = `/${this.coverageDirectory}/`;
|
|
1612
|
-
project.gitignore.addPatterns(coveragePath);
|
|
1613
|
-
project.npmignore?.exclude(coveragePath);
|
|
1614
|
-
this.addTestTasks();
|
|
1615
|
-
this.synthesizeConfig();
|
|
1616
|
-
}
|
|
1617
|
-
/**
|
|
1618
|
-
* Find the Vitest component on a project.
|
|
1619
|
-
*/
|
|
1620
|
-
static of(project) {
|
|
1621
|
-
const isVitest = (c) => c instanceof _Vitest;
|
|
1622
|
-
return project.components.find(isVitest);
|
|
1623
|
-
}
|
|
1624
|
-
preSynthesize() {
|
|
1625
|
-
super.preSynthesize();
|
|
1626
|
-
for (const component of this.project.components) {
|
|
1627
|
-
if (component instanceof Jest) {
|
|
1628
|
-
throw new Error("Vitest cannot be used together with Jest");
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
addTestTasks() {
|
|
1633
|
-
this.project.testTask.exec("vitest run --update");
|
|
1634
|
-
if (!this.project.tasks.tryFind("test:watch")) {
|
|
1635
|
-
this.project.addTask("test:watch", {
|
|
1636
|
-
description: "Run tests in watch mode",
|
|
1637
|
-
exec: "vitest watch",
|
|
1638
|
-
receiveArgs: true
|
|
1639
|
-
});
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
synthesizeConfig() {
|
|
1643
|
-
this.project.tryRemoveFile(this.configFilePath);
|
|
1644
|
-
new TextFile3(this, this.configFilePath, {
|
|
1645
|
-
lines: this.renderConfig()
|
|
1646
|
-
});
|
|
1647
|
-
}
|
|
1648
|
-
renderConfig() {
|
|
1649
|
-
return [
|
|
1650
|
-
'import { defineConfig } from "vitest/config";',
|
|
1651
|
-
"",
|
|
1652
|
-
"export default defineConfig({",
|
|
1653
|
-
" test: {",
|
|
1654
|
-
` include: ${JSON.stringify(this.include)},`,
|
|
1655
|
-
` exclude: ${JSON.stringify(this.exclude)},`,
|
|
1656
|
-
` environment: "${this.environment}",`,
|
|
1657
|
-
` passWithNoTests: ${this.passWithNoTests},`,
|
|
1658
|
-
" coverage: {",
|
|
1659
|
-
` enabled: ${this.coverageEnabled},`,
|
|
1660
|
-
` provider: "v8",`,
|
|
1661
|
-
` reportsDirectory: "${this.coverageDirectory}",`,
|
|
1662
|
-
` reporter: ${JSON.stringify(this.coverageReporters)},`,
|
|
1663
|
-
" },",
|
|
1664
|
-
" },",
|
|
1665
|
-
"});"
|
|
1666
|
-
];
|
|
1667
|
-
}
|
|
1668
|
-
};
|
|
1669
|
-
|
|
1670
|
-
// src/projects/typescript-project.ts
|
|
1671
2271
|
var TestRunner = {
|
|
1672
2272
|
JEST: "jest",
|
|
1673
2273
|
VITEST: "vitest"
|
|
@@ -2282,6 +2882,9 @@ var MonorepoProject = class extends TypeScriptAppProject {
|
|
|
2282
2882
|
if (options.approveMergeUpgradeOptions) {
|
|
2283
2883
|
addApproveMergeUpgradeWorkflow(this, options.approveMergeUpgradeOptions);
|
|
2284
2884
|
}
|
|
2885
|
+
if (options.agentConfig) {
|
|
2886
|
+
new AgentConfig(this, options.agentConfigOptions);
|
|
2887
|
+
}
|
|
2285
2888
|
if (this.buildWorkflow) {
|
|
2286
2889
|
addBuildCompleteJob(this.buildWorkflow);
|
|
2287
2890
|
}
|
|
@@ -2369,7 +2972,7 @@ var TypeScriptConfig = class extends Component13 {
|
|
|
2369
2972
|
};
|
|
2370
2973
|
|
|
2371
2974
|
// src/workflows/aws-deploy-workflow.ts
|
|
2372
|
-
var
|
|
2975
|
+
var import_utils10 = __toESM(require_lib());
|
|
2373
2976
|
import { Component as Component14 } from "projen";
|
|
2374
2977
|
import { BuildWorkflow } from "projen/lib/build";
|
|
2375
2978
|
import { GitHub } from "projen/lib/github";
|
|
@@ -2386,7 +2989,7 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends Component14 {
|
|
|
2386
2989
|
* @deprecated Use deployment target role terminology elsewhere. This property is maintained for backward compatibility.
|
|
2387
2990
|
* @default 'primary' (this is the only type supported currently)
|
|
2388
2991
|
*/
|
|
2389
|
-
this.awsEnvironmentType =
|
|
2992
|
+
this.awsEnvironmentType = import_utils10.DEPLOYMENT_TARGET_ROLE.PRIMARY;
|
|
2390
2993
|
this.setupNode = () => {
|
|
2391
2994
|
return [
|
|
2392
2995
|
{
|
|
@@ -2496,7 +3099,7 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends Component14 {
|
|
|
2496
3099
|
}
|
|
2497
3100
|
const turbo = TurboRepo.of(this.rootProject);
|
|
2498
3101
|
const buildWorkflowOptions = turbo?.remoteCacheOptions ? TurboRepo.buildWorkflowOptions(turbo.remoteCacheOptions) : {};
|
|
2499
|
-
this.awsStageType = options.awsStageType ??
|
|
3102
|
+
this.awsStageType = options.awsStageType ?? import_utils10.AWS_STAGE_TYPE.DEV;
|
|
2500
3103
|
this.awsDeploymentTargets = options.awsDeploymentTargets ?? AwsDeploymentConfig.of(project)?.awsDeploymentTargets.filter(
|
|
2501
3104
|
(target) => target.awsStageType === this.awsStageType && target.ciDeployment
|
|
2502
3105
|
) ?? [];
|
|
@@ -2671,6 +3274,14 @@ export {
|
|
|
2671
3274
|
Vitest,
|
|
2672
3275
|
addApproveMergeUpgradeWorkflow,
|
|
2673
3276
|
addBuildCompleteJob,
|
|
2674
|
-
|
|
3277
|
+
awsCdkBundle,
|
|
3278
|
+
baseBundle,
|
|
3279
|
+
getLatestEligibleVersion,
|
|
3280
|
+
jestBundle,
|
|
3281
|
+
pnpmBundle,
|
|
3282
|
+
projenBundle,
|
|
3283
|
+
turborepoBundle,
|
|
3284
|
+
typescriptBundle,
|
|
3285
|
+
vitestBundle
|
|
2675
3286
|
};
|
|
2676
3287
|
//# sourceMappingURL=index.mjs.map
|