@codedrifters/configulator 0.0.154 → 0.0.156
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 +382 -2
- package/lib/index.d.ts +383 -3
- package/lib/index.js +1386 -565
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1340 -529
- 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 Component8 } from "projen";
|
|
184
177
|
|
|
185
178
|
// src/agent/types.ts
|
|
186
179
|
var AGENT_RULE_SCOPE = {
|
|
@@ -210,7 +203,1135 @@ 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
|
+
"**Repository:** {{repository.owner}}/{{repository.name}}",
|
|
300
|
+
"**Default branch:** {{repository.defaultBranch}}",
|
|
301
|
+
"",
|
|
302
|
+
"## Important Notes",
|
|
303
|
+
"",
|
|
304
|
+
"- **Never edit generated files** \u2014 they are marked with `// ~~ Generated by projen`",
|
|
305
|
+
"- **After modifying Projen configuration**, the user should run `npx projen` locally. The agent must not run `npx projen`, `pnpm install`, or `pnpm i`.",
|
|
306
|
+
"- **Configure dependencies through Projen** \u2014 never use `npm install`, `pnpm add`, or `yarn add`. Add them to `deps` or `devDeps` in Projen config.",
|
|
307
|
+
"- **Export from index.ts** to maintain clean public APIs"
|
|
308
|
+
].join("\n"),
|
|
309
|
+
tags: ["project"]
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
name: "interaction-style",
|
|
313
|
+
description: "Interaction style \u2014 ask questions one at a time and wait for feedback",
|
|
314
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
315
|
+
content: [
|
|
316
|
+
"# Interaction Style Guidelines",
|
|
317
|
+
"",
|
|
318
|
+
"When responding to requests, follow these interaction principles.",
|
|
319
|
+
"",
|
|
320
|
+
"1. **Ask questions one at a time**: When clarification is needed, ask a single question and wait for the user's response before proceeding.",
|
|
321
|
+
"2. **Wait for feedback**: After asking a question, pause and wait for the user's answer before asking additional questions or making assumptions.",
|
|
322
|
+
"3. **Avoid question overload**: Do not ask multiple questions in a single response. If multiple clarifications are needed, prioritize the most important question first.",
|
|
323
|
+
"4. **Progressive clarification**: Once the user answers your first question, you may then ask the next most important question if needed.",
|
|
324
|
+
"5. **Confirm understanding**: After receiving feedback, acknowledge the user's response before proceeding with the next step or question.",
|
|
325
|
+
"6. **Be patient**: Do not rush ahead with assumptions. It is better to ask one clarifying question than to proceed with incorrect assumptions."
|
|
326
|
+
].join("\n"),
|
|
327
|
+
tags: ["project"]
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: "general-conventions",
|
|
331
|
+
description: "Code formatting (Prettier/ESLint), import conventions (ES modules, import order), error handling (async/await, no floating promises)",
|
|
332
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
333
|
+
filePatterns: ["**/*.ts", "**/*.tsx"],
|
|
334
|
+
content: [
|
|
335
|
+
"# General Conventions",
|
|
336
|
+
"",
|
|
337
|
+
"## Code Formatting",
|
|
338
|
+
"",
|
|
339
|
+
"- Use **Prettier** for formatting (runs automatically on save in VS Code)",
|
|
340
|
+
"- Always use curly braces for control flow, even single-line statements",
|
|
341
|
+
"- Prefer `const` over `let`; avoid `var`",
|
|
342
|
+
"- Use trailing commas in multi-line objects/arrays",
|
|
343
|
+
"",
|
|
344
|
+
"### ESLint Rules to Follow",
|
|
345
|
+
"",
|
|
346
|
+
"- `curly`: Always use curly braces (multi-line, consistent)",
|
|
347
|
+
"- `dot-notation`: Use dot notation over bracket notation",
|
|
348
|
+
"- `no-bitwise`: No bitwise operators",
|
|
349
|
+
"- `@typescript-eslint/no-shadow`: No variable shadowing",
|
|
350
|
+
"- `@typescript-eslint/member-ordering`: Follow member order",
|
|
351
|
+
"",
|
|
352
|
+
"## Import Conventions",
|
|
353
|
+
"",
|
|
354
|
+
"- **Always use ES modules** (`import`/`export`), never `require()`",
|
|
355
|
+
"- Import order:",
|
|
356
|
+
" 1. Built-in Node.js modules (e.g., `node:path`, `node:fs`)",
|
|
357
|
+
" 2. External dependencies (alphabetically sorted)",
|
|
358
|
+
" 3. Internal imports (relative paths)",
|
|
359
|
+
"- Group imports with blank lines between groups",
|
|
360
|
+
"- Alphabetize imports within each group (case-insensitive)",
|
|
361
|
+
"",
|
|
362
|
+
"## Error Handling",
|
|
363
|
+
"",
|
|
364
|
+
"- Always handle promises properly with `await`",
|
|
365
|
+
"- Use `@typescript-eslint/return-await` rule (always return await)",
|
|
366
|
+
"- Never leave floating promises (`@typescript-eslint/no-floating-promises`)",
|
|
367
|
+
"- Use proper error types and meaningful error messages",
|
|
368
|
+
"- Do not swallow errors or use empty catch blocks",
|
|
369
|
+
"- Prefer async/await over raw promises"
|
|
370
|
+
].join("\n"),
|
|
371
|
+
tags: ["coding"]
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
name: "pull-request-conventions",
|
|
375
|
+
description: "Conventional commit PR titles, closing keywords, change summaries",
|
|
376
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
377
|
+
content: [
|
|
378
|
+
"# Pull Request Conventions",
|
|
379
|
+
"",
|
|
380
|
+
"## PR Title Prefix",
|
|
381
|
+
"",
|
|
382
|
+
"**Always** use a **conventional commit prefix** in the PR `title`. Format: `type: description` or `type(scope): description`.",
|
|
383
|
+
"",
|
|
384
|
+
"| Prefix | Use for |",
|
|
385
|
+
"|--------|---------|",
|
|
386
|
+
"| `feat:` | New features or functionality |",
|
|
387
|
+
"| `fix:` | Bug fixes |",
|
|
388
|
+
"| `docs:` | Documentation-only changes |",
|
|
389
|
+
"| `chore:` | Maintenance: deps, tooling, config |",
|
|
390
|
+
"| `refactor:` | Code restructure, no behavior change |",
|
|
391
|
+
"| `release:` | Release preparation, version bumps |",
|
|
392
|
+
"| `hotfix:` | Urgent production fixes |",
|
|
393
|
+
"",
|
|
394
|
+
"## Link to the Issue",
|
|
395
|
+
"",
|
|
396
|
+
"When the PR addresses an issue, **always** include a closing keyword in the PR body:",
|
|
397
|
+
"- `Closes #<issue>`, `Fixes #<issue>`, or `Resolves #<issue>`",
|
|
398
|
+
"",
|
|
399
|
+
"## Summary of Changes",
|
|
400
|
+
"",
|
|
401
|
+
"Every PR must include a **summary of the changes** made. Use bullet points or short paragraphs. Do not leave the description empty.",
|
|
402
|
+
"",
|
|
403
|
+
"## Commit Messages",
|
|
404
|
+
"",
|
|
405
|
+
"Use **conventional commits** for git commit messages: `type: short description`. Do not add AI co-author or attribution."
|
|
406
|
+
].join("\n"),
|
|
407
|
+
tags: ["workflow"]
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
name: "branch-naming-conventions",
|
|
411
|
+
description: "Branch format (type/[issue-]description), create-on-GitHub-then-fetch workflow",
|
|
412
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
413
|
+
content: [
|
|
414
|
+
"# Branch Naming Conventions",
|
|
415
|
+
"",
|
|
416
|
+
"## Format",
|
|
417
|
+
"",
|
|
418
|
+
"```",
|
|
419
|
+
"<type>/[<issue>-]<description>",
|
|
420
|
+
"```",
|
|
421
|
+
"",
|
|
422
|
+
"- **type** (required): One of `feat`, `fix`, `docs`, `chore`, `refactor`, `release`, `hotfix`",
|
|
423
|
+
"- **issue** (optional): Issue number (e.g., `25`). Include when known.",
|
|
424
|
+
"- **description** (required): Short, lowercase, kebab-case summary",
|
|
425
|
+
"",
|
|
426
|
+
"## Examples",
|
|
427
|
+
"",
|
|
428
|
+
"- `feat/25-add-cursor-rules`",
|
|
429
|
+
"- `fix/23-rename-cursor-rules-mdc`",
|
|
430
|
+
"- `chore/upgrade-eslint`",
|
|
431
|
+
"- `docs/update-readme`"
|
|
432
|
+
].join("\n"),
|
|
433
|
+
tags: ["workflow"]
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
name: "issue-conventions",
|
|
437
|
+
description: "Issue title prefixes, GitHub issue type mapping, prerequisite issues",
|
|
438
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
439
|
+
content: [
|
|
440
|
+
"# Issue Title Conventions",
|
|
441
|
+
"",
|
|
442
|
+
"## Format",
|
|
443
|
+
"",
|
|
444
|
+
"```",
|
|
445
|
+
"<type>: <description>",
|
|
446
|
+
"```",
|
|
447
|
+
"",
|
|
448
|
+
"## Types",
|
|
449
|
+
"",
|
|
450
|
+
"| Prefix | Use for |",
|
|
451
|
+
"|--------|---------|",
|
|
452
|
+
"| `epic:` | Large initiatives spanning multiple child issues |",
|
|
453
|
+
"| `feat:` | New features or functionality |",
|
|
454
|
+
"| `fix:` | Bug fixes |",
|
|
455
|
+
"| `chore:` | Maintenance: deps, tooling, config |",
|
|
456
|
+
"| `docs:` | Documentation-only work |",
|
|
457
|
+
"| `refactor:` | Code restructure, no behavior change |",
|
|
458
|
+
"| `release:` | Release preparation, version bumps |",
|
|
459
|
+
"| `hotfix:` | Urgent production fixes |",
|
|
460
|
+
"",
|
|
461
|
+
"## Prerequisite Issues",
|
|
462
|
+
"",
|
|
463
|
+
"Include any prerequisite (blocking) issues in the issue body when they exist.",
|
|
464
|
+
"Use a **Dependencies** section or `**Depends on:** #123`."
|
|
465
|
+
].join("\n"),
|
|
466
|
+
tags: ["workflow"]
|
|
467
|
+
}
|
|
468
|
+
]
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// src/agent/bundles/jest.ts
|
|
472
|
+
var jestBundle = {
|
|
473
|
+
name: "jest",
|
|
474
|
+
description: "Jest testing conventions and patterns",
|
|
475
|
+
appliesWhen: (project) => hasDep(project, "jest"),
|
|
476
|
+
rules: [
|
|
477
|
+
{
|
|
478
|
+
name: "jest-testing",
|
|
479
|
+
description: "Jest testing conventions and patterns",
|
|
480
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
481
|
+
filePatterns: ["**/*.test.ts", "**/*.spec.ts"],
|
|
482
|
+
content: [
|
|
483
|
+
"# Jest Testing Patterns",
|
|
484
|
+
"",
|
|
485
|
+
"## Mandatory Requirements",
|
|
486
|
+
"",
|
|
487
|
+
"- **Tests MUST be created or updated whenever code functionality is added or changed**",
|
|
488
|
+
"- This applies to all code changes, including:",
|
|
489
|
+
" - New features and functionality",
|
|
490
|
+
" - Bug fixes",
|
|
491
|
+
" - Refactoring that changes behavior",
|
|
492
|
+
" - API changes",
|
|
493
|
+
" - Configuration changes that affect functionality",
|
|
494
|
+
"- Tests should be written or updated as part of the same change that modifies the code",
|
|
495
|
+
"",
|
|
496
|
+
"## Test Structure",
|
|
497
|
+
"",
|
|
498
|
+
"- Use **Jest** with SWC for fast compilation",
|
|
499
|
+
"- Test files: `.spec.ts` or `.test.ts` (co-located with source)",
|
|
500
|
+
"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`",
|
|
501
|
+
"- Prefer snapshot tests for complex object structures",
|
|
502
|
+
"- Mock external dependencies appropriately",
|
|
503
|
+
"",
|
|
504
|
+
"## Test Organization",
|
|
505
|
+
"",
|
|
506
|
+
"- Co-locate test files with source files",
|
|
507
|
+
"- Test files can use dev dependencies (ESLint rule override)",
|
|
508
|
+
"- Use `@swc/jest` for fast compilation",
|
|
509
|
+
"- Configure Jest in `jest.config.json` (not in package.json)",
|
|
510
|
+
"",
|
|
511
|
+
"## Example Test Structure",
|
|
512
|
+
"",
|
|
513
|
+
"```typescript",
|
|
514
|
+
"import { MyClass } from './my-class';",
|
|
515
|
+
"",
|
|
516
|
+
"describe('MyClass', () => {",
|
|
517
|
+
" it('should do something specific', () => {",
|
|
518
|
+
" // Test implementation",
|
|
519
|
+
" });",
|
|
520
|
+
"});",
|
|
521
|
+
"```"
|
|
522
|
+
].join("\n"),
|
|
523
|
+
tags: ["testing"]
|
|
524
|
+
}
|
|
525
|
+
]
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
// src/pnpm/pnpm-workspace.ts
|
|
529
|
+
import { relative } from "path";
|
|
530
|
+
import { Component, YamlFile } from "projen";
|
|
531
|
+
var MIMIMUM_RELEASE_AGE = {
|
|
532
|
+
ZERO_DAYS: 0,
|
|
533
|
+
ONE_HOUR: 60,
|
|
534
|
+
SIX_HOURS: 360,
|
|
535
|
+
TWELVE_HOURS: 720,
|
|
536
|
+
ONE_DAY: 1440,
|
|
537
|
+
TWO_DAYS: 2880,
|
|
538
|
+
THREE_DAYS: 4320,
|
|
539
|
+
FOUR_DAYS: 5760,
|
|
540
|
+
FIVE_DAYS: 7200,
|
|
541
|
+
SIX_DAYS: 8640,
|
|
542
|
+
ONE_WEEK: 10080
|
|
543
|
+
};
|
|
544
|
+
var PnpmWorkspace = class _PnpmWorkspace extends Component {
|
|
545
|
+
/**
|
|
546
|
+
* Get the pnpm workspace component of a project. If it does not exist,
|
|
547
|
+
* return undefined.
|
|
548
|
+
*
|
|
549
|
+
* @param project
|
|
550
|
+
* @returns
|
|
551
|
+
*/
|
|
552
|
+
static of(project) {
|
|
553
|
+
const isDefined = (c) => c instanceof _PnpmWorkspace;
|
|
554
|
+
return project.root.components.find(isDefined);
|
|
555
|
+
}
|
|
556
|
+
constructor(project, options = {}) {
|
|
557
|
+
super(project);
|
|
558
|
+
project.tryFindObjectFile("package.json")?.addDeletionOverride("pnpm");
|
|
559
|
+
this.fileName = options.fileName ?? "pnpm-workspace.yaml";
|
|
560
|
+
this.minimumReleaseAge = options.minimumReleaseAge ?? MIMIMUM_RELEASE_AGE.ONE_DAY;
|
|
561
|
+
this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude ? ["@codedrifters/*", ...options.minimumReleaseAgeExclude] : ["@codedrifters/*"];
|
|
562
|
+
this.onlyBuiltDependencies = options.onlyBuiltDependencies ? options.onlyBuiltDependencies : [];
|
|
563
|
+
this.ignoredBuiltDependencies = options.ignoredBuiltDependencies ? options.ignoredBuiltDependencies : [];
|
|
564
|
+
this.subprojects = options.subprojects ?? [];
|
|
565
|
+
this.defaultCatalog = options.defaultCatalog;
|
|
566
|
+
this.namedCatalogs = options.namedCatalogs;
|
|
567
|
+
project.addPackageIgnore(this.fileName);
|
|
568
|
+
new YamlFile(this.project, this.fileName, {
|
|
569
|
+
obj: () => {
|
|
570
|
+
const pnpmConfig = {};
|
|
571
|
+
const packages = new Array();
|
|
572
|
+
for (const subproject of project.subprojects) {
|
|
573
|
+
packages.push(relative(this.project.outdir, subproject.outdir));
|
|
574
|
+
}
|
|
575
|
+
const packageSet = new Set(packages);
|
|
576
|
+
for (const subprojectPath of this.subprojects) {
|
|
577
|
+
packageSet.add(subprojectPath);
|
|
578
|
+
}
|
|
579
|
+
if (this.subprojects.length > 0) {
|
|
580
|
+
packages.length = 0;
|
|
581
|
+
packages.push(...packageSet);
|
|
582
|
+
}
|
|
583
|
+
pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;
|
|
584
|
+
if (this.minimumReleaseAgeExclude.length > 0) {
|
|
585
|
+
pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;
|
|
586
|
+
}
|
|
587
|
+
if (this.onlyBuiltDependencies.length > 0) {
|
|
588
|
+
pnpmConfig.onlyBuiltDependencies = this.onlyBuiltDependencies;
|
|
589
|
+
}
|
|
590
|
+
if (this.ignoredBuiltDependencies.length > 0) {
|
|
591
|
+
pnpmConfig.ignoreBuiltDependencies = this.ignoredBuiltDependencies;
|
|
592
|
+
}
|
|
593
|
+
if (this.defaultCatalog && Object.keys(this.defaultCatalog).length > 0) {
|
|
594
|
+
pnpmConfig.catalog = this.defaultCatalog;
|
|
595
|
+
}
|
|
596
|
+
if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {
|
|
597
|
+
pnpmConfig.namedCatalogs = this.namedCatalogs;
|
|
598
|
+
}
|
|
599
|
+
return {
|
|
600
|
+
...packages.length > 0 ? { packages } : {},
|
|
601
|
+
...pnpmConfig ? { ...pnpmConfig } : {}
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
// src/agent/bundles/pnpm.ts
|
|
609
|
+
var pnpmBundle = {
|
|
610
|
+
name: "pnpm",
|
|
611
|
+
description: "PNPM workspace rules and dependency management conventions",
|
|
612
|
+
appliesWhen: (project) => hasComponent(project, PnpmWorkspace),
|
|
613
|
+
rules: [
|
|
614
|
+
{
|
|
615
|
+
name: "pnpm-workspace",
|
|
616
|
+
description: "PNPM workspace and dependency management conventions",
|
|
617
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
618
|
+
filePatterns: ["package.json", "pnpm-workspace.yaml", "pnpm-lock.yaml"],
|
|
619
|
+
content: [
|
|
620
|
+
"# PNPM Workspace Conventions",
|
|
621
|
+
"",
|
|
622
|
+
"## Package Management",
|
|
623
|
+
"",
|
|
624
|
+
"- Use **PNPM** for package management",
|
|
625
|
+
"- Workspace configuration in `pnpm-workspace.yaml`",
|
|
626
|
+
"- Dependencies managed through Projen, not directly in `package.json`",
|
|
627
|
+
"- **Always use workspace dependencies** (`workspace:*` or `workspace:^`) for packages within this monorepo",
|
|
628
|
+
"- Never use published NPM versions of internal packages; always reference the local workspace version",
|
|
629
|
+
"",
|
|
630
|
+
"## Dependency Management",
|
|
631
|
+
"",
|
|
632
|
+
"**DO:**",
|
|
633
|
+
"- Configure dependencies in Projen configuration files (`.projenrc.ts` or `projenrc/*.ts`)",
|
|
634
|
+
"- Add dependencies to `deps`, `devDeps`, or `peerDeps` arrays in project configuration",
|
|
635
|
+
'- Use catalog dependencies when available (e.g., `"aws-cdk-lib@catalog:"`)',
|
|
636
|
+
"- Ask the user to run `npx projen` and `pnpm install` after updating dependency configuration",
|
|
637
|
+
"",
|
|
638
|
+
"**DO NOT:**",
|
|
639
|
+
"- Run `npm install some-package`",
|
|
640
|
+
"- Run `pnpm add some-package`",
|
|
641
|
+
"- Run `yarn add some-package`",
|
|
642
|
+
"- Manually edit `package.json` dependencies",
|
|
643
|
+
"",
|
|
644
|
+
"Manual package installation creates conflicts with Projen-managed files."
|
|
645
|
+
].join("\n"),
|
|
646
|
+
tags: ["workflow"]
|
|
647
|
+
}
|
|
648
|
+
]
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
// src/agent/bundles/projen.ts
|
|
652
|
+
var projenBundle = {
|
|
653
|
+
name: "projen",
|
|
654
|
+
description: "Projen conventions, synthesis workflow, .projenrc.ts patterns",
|
|
655
|
+
appliesWhen: (project) => hasDep(project, "projen"),
|
|
656
|
+
rules: [
|
|
657
|
+
{
|
|
658
|
+
name: "projen-conventions",
|
|
659
|
+
description: "Projen configuration patterns and best practices",
|
|
660
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
661
|
+
filePatterns: ["projenrc/**/*.ts", ".projenrc.ts"],
|
|
662
|
+
content: [
|
|
663
|
+
"# Projen Conventions",
|
|
664
|
+
"",
|
|
665
|
+
"## Configuration Management",
|
|
666
|
+
"",
|
|
667
|
+
"- **Never edit generated files** (`package.json`, `tsconfig.json`, etc. marked with `// ~~ Generated by projen`)",
|
|
668
|
+
"- Edit Projen configuration in:",
|
|
669
|
+
" - `.projenrc.ts` (root)",
|
|
670
|
+
" - `projenrc/*.ts` (package-specific)",
|
|
671
|
+
"- After making Projen changes, ask the user to run `npx projen` locally (agent must not run it)",
|
|
672
|
+
"",
|
|
673
|
+
"## Custom Projen Components",
|
|
674
|
+
"",
|
|
675
|
+
"All custom components must extend `Component` from Projen and use a static `.of()` factory for discovery:",
|
|
676
|
+
"",
|
|
677
|
+
"```typescript",
|
|
678
|
+
"export class MyComponent extends Component {",
|
|
679
|
+
" public static of(project: Project): MyComponent | undefined {",
|
|
680
|
+
" const isDefined = (c: Component): c is MyComponent =>",
|
|
681
|
+
" c instanceof MyComponent;",
|
|
682
|
+
" return project.components.find(isDefined);",
|
|
683
|
+
" }",
|
|
684
|
+
"",
|
|
685
|
+
" constructor(project: Project, options: MyComponentOptions) {",
|
|
686
|
+
" super(project);",
|
|
687
|
+
" // Implementation",
|
|
688
|
+
" }",
|
|
689
|
+
"}",
|
|
690
|
+
"```",
|
|
691
|
+
"",
|
|
692
|
+
"## Component Authoring",
|
|
693
|
+
"",
|
|
694
|
+
"- Export project types and utilities from `index.ts`",
|
|
695
|
+
"- Follow Projen's component lifecycle patterns",
|
|
696
|
+
"- Use `merge` from `ts-deepmerge` for deep merging configuration objects",
|
|
697
|
+
"- Components should be reusable and configurable; use TypeScript interfaces for component options",
|
|
698
|
+
"- Provide sensible defaults while allowing customization",
|
|
699
|
+
"- Document public APIs with minimal JSDoc; put extended documentation in markdown",
|
|
700
|
+
"",
|
|
701
|
+
"## Dependencies",
|
|
702
|
+
"",
|
|
703
|
+
"- Dependencies managed through Projen configuration, not directly in `package.json`",
|
|
704
|
+
'- Use catalog dependencies when available (e.g., `"projen": "catalog:"`)',
|
|
705
|
+
"- Peer dependencies for shared libraries (e.g., `constructs`, `projen`, `aws-cdk-lib`)",
|
|
706
|
+
'- Use workspace protocol for internal packages: `"@org/pkg@workspace:*"`'
|
|
707
|
+
].join("\n"),
|
|
708
|
+
tags: ["workflow"]
|
|
709
|
+
}
|
|
710
|
+
]
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
// src/turbo/turbo-repo.ts
|
|
714
|
+
import { Component as Component3, FileBase, JsonFile } from "projen/lib";
|
|
715
|
+
import { JobPermission } from "projen/lib/github/workflows-model";
|
|
716
|
+
|
|
717
|
+
// src/turbo/turbo-repo-task.ts
|
|
718
|
+
import { Component as Component2 } from "projen/lib";
|
|
719
|
+
var TurboRepoTask = class extends Component2 {
|
|
720
|
+
constructor(project, options) {
|
|
721
|
+
super(project);
|
|
722
|
+
this.project = project;
|
|
723
|
+
this.name = options.name;
|
|
724
|
+
this.dependsOn = options.dependsOn ?? [];
|
|
725
|
+
this.env = options.env ?? [];
|
|
726
|
+
this.passThroughEnv = options.passThroughEnv ?? [];
|
|
727
|
+
this.outputs = options.outputs ?? [];
|
|
728
|
+
this.cache = options.cache ?? true;
|
|
729
|
+
this.inputs = [
|
|
730
|
+
...options.inputs ?? [],
|
|
731
|
+
// rerun if projen config changes
|
|
732
|
+
".projen/**",
|
|
733
|
+
// ignore mac files
|
|
734
|
+
"!.DS_Store",
|
|
735
|
+
"!**/.DS_Store"
|
|
736
|
+
];
|
|
737
|
+
this.outputLogs = options.outputLogs ?? "new-only";
|
|
738
|
+
this.persistent = options.persistent ?? false;
|
|
739
|
+
this.interactive = options.interactive ?? false;
|
|
740
|
+
this.isActive = true;
|
|
741
|
+
}
|
|
742
|
+
taskConfig() {
|
|
743
|
+
return {
|
|
744
|
+
dependsOn: this.dependsOn,
|
|
745
|
+
env: this.env,
|
|
746
|
+
passThroughEnv: this.passThroughEnv,
|
|
747
|
+
outputs: this.outputs,
|
|
748
|
+
cache: this.cache,
|
|
749
|
+
inputs: this.inputs,
|
|
750
|
+
outputLogs: this.outputLogs,
|
|
751
|
+
persistent: this.persistent,
|
|
752
|
+
interactive: this.interactive
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
// src/turbo/turbo-repo.ts
|
|
758
|
+
var ROOT_TURBO_TASK_NAME = "turbo:build";
|
|
759
|
+
var ROOT_CI_TASK_NAME = "build:all";
|
|
760
|
+
var _TurboRepo = class _TurboRepo extends Component3 {
|
|
761
|
+
constructor(project, options = {}) {
|
|
762
|
+
super(project);
|
|
763
|
+
this.project = project;
|
|
764
|
+
/**
|
|
765
|
+
* Sub-Tasks to run
|
|
766
|
+
*/
|
|
767
|
+
this.tasks = [];
|
|
768
|
+
this.turboVersion = options.turboVersion ?? "catalog:";
|
|
769
|
+
this.isRootProject = project === project.root;
|
|
770
|
+
if (this.isRootProject) {
|
|
771
|
+
project.addDevDeps(`turbo@${this.turboVersion}`);
|
|
772
|
+
}
|
|
773
|
+
project.gitignore.addPatterns("/.turbo");
|
|
774
|
+
project.npmignore?.addPatterns("/.turbo/");
|
|
775
|
+
this.extends = options.extends ?? (this.isRootProject ? [] : ["//"]);
|
|
776
|
+
this.globalDependencies = options.globalDependencies ?? [];
|
|
777
|
+
this.globalEnv = options.globalEnv ?? [];
|
|
778
|
+
this.globalPassThroughEnv = options.globalPassThroughEnv ?? [];
|
|
779
|
+
this.ui = options.ui ?? "stream";
|
|
780
|
+
this.dangerouslyDisablePackageManagerCheck = options.dangerouslyDisablePackageManagerCheck ?? false;
|
|
781
|
+
this.cacheDir = options.cacheDir ?? ".turbo/cache";
|
|
782
|
+
this.daemon = options.daemon ?? true;
|
|
783
|
+
this.envMode = options.envMode ?? "strict";
|
|
784
|
+
this.remoteCacheOptions = options.remoteCacheOptions;
|
|
785
|
+
this.buildAllTaskEnvVars = options.buildAllTaskEnvVars ?? {};
|
|
786
|
+
const rootGeneratedFiles = this.isRootProject ? this.project.components.filter((c) => c instanceof FileBase).map((c) => c.path) : [];
|
|
787
|
+
this.buildTask = new TurboRepoTask(this.project, {
|
|
788
|
+
name: ROOT_TURBO_TASK_NAME,
|
|
789
|
+
dependsOn: this.isRootProject ? [`^${ROOT_TURBO_TASK_NAME}`] : [],
|
|
790
|
+
...rootGeneratedFiles.length > 0 && { inputs: rootGeneratedFiles }
|
|
791
|
+
});
|
|
792
|
+
if (this.isRootProject) {
|
|
793
|
+
this.buildAllTask = this.project.tasks.addTask(ROOT_CI_TASK_NAME, {
|
|
794
|
+
description: "Root build followed by sub-project builds. Mimics the CI build process in one step."
|
|
795
|
+
});
|
|
796
|
+
this.buildAllTask.exec("turbo telemetry disable");
|
|
797
|
+
if (this.buildAllTaskEnvVars) {
|
|
798
|
+
Object.entries(this.buildAllTaskEnvVars).forEach(([name, value]) => {
|
|
799
|
+
this.addGlobalEnvVar(name, value);
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
if (!this.remoteCacheOptions) {
|
|
803
|
+
this.buildAllTask.exec(
|
|
804
|
+
`turbo ${ROOT_TURBO_TASK_NAME} --summarize --concurrency=10`
|
|
805
|
+
);
|
|
806
|
+
} else {
|
|
807
|
+
this.buildAllTask.exec(
|
|
808
|
+
`turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,
|
|
809
|
+
{
|
|
810
|
+
condition: '[ ! -n "$CI" ]',
|
|
811
|
+
env: {
|
|
812
|
+
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,
|
|
813
|
+
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
);
|
|
817
|
+
this.buildAllTask.exec(
|
|
818
|
+
`turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,
|
|
819
|
+
{
|
|
820
|
+
condition: '[ -n "$CI" ]',
|
|
821
|
+
env: {
|
|
822
|
+
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text)`,
|
|
823
|
+
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text)`
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
if (!this.isRootProject) {
|
|
830
|
+
const generatedFiles = this.project.components.filter((c) => c instanceof FileBase).map((c) => c.path);
|
|
831
|
+
this.preCompileTask = new TurboRepoTask(project, {
|
|
832
|
+
name: options.preCompileTask?.name ?? "pre-compile",
|
|
833
|
+
inputs: ["src/**", ...generatedFiles]
|
|
834
|
+
});
|
|
835
|
+
this.compileTask = new TurboRepoTask(project, {
|
|
836
|
+
name: options.compileTask?.name ?? "compile",
|
|
837
|
+
inputs: ["src/**", ...generatedFiles]
|
|
838
|
+
});
|
|
839
|
+
this.postCompileTask = new TurboRepoTask(project, {
|
|
840
|
+
name: options.postCompileTask?.name ?? "post-compile",
|
|
841
|
+
inputs: ["src/**", ...generatedFiles]
|
|
842
|
+
});
|
|
843
|
+
this.testTask = new TurboRepoTask(project, {
|
|
844
|
+
name: options.testTask?.name ?? "test"
|
|
845
|
+
});
|
|
846
|
+
this.packageTask = new TurboRepoTask(project, {
|
|
847
|
+
name: options.packageTask?.name ?? "package",
|
|
848
|
+
inputs: [".npmignore"]
|
|
849
|
+
});
|
|
850
|
+
this.tasks.push(
|
|
851
|
+
this.preCompileTask,
|
|
852
|
+
this.compileTask,
|
|
853
|
+
this.postCompileTask,
|
|
854
|
+
this.testTask,
|
|
855
|
+
this.packageTask
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Static method to discovert turbo in a project.
|
|
861
|
+
*/
|
|
862
|
+
static of(project) {
|
|
863
|
+
const isDefined = (c) => c instanceof _TurboRepo;
|
|
864
|
+
return project.components.find(isDefined);
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Add an env var to the global env vars for all tasks.
|
|
868
|
+
* This will also become an input for the build:all task cache at the root.
|
|
869
|
+
*/
|
|
870
|
+
addGlobalEnvVar(name, value) {
|
|
871
|
+
this.buildAllTask?.env(name, value);
|
|
872
|
+
if (this.isRootProject) {
|
|
873
|
+
this.globalEnv.push(name);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* Sets GIT_BRANCH_NAME so root tasks (e.g. build:all) pass the current branch.
|
|
878
|
+
* Value must be exactly $(...) so Projen's task runtime expands it; the shell
|
|
879
|
+
* then expands ${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}.
|
|
880
|
+
*/
|
|
881
|
+
activateBranchNameEnvVar() {
|
|
882
|
+
this.addGlobalEnvVar(
|
|
883
|
+
"GIT_BRANCH_NAME",
|
|
884
|
+
'$(echo "${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}")'
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
preSynthesize() {
|
|
888
|
+
let nextDependsOn = this.project.deps.all.filter((d) => d.version === "workspace:*").map((d) => [d.name, ROOT_TURBO_TASK_NAME].join("#"));
|
|
889
|
+
if (!this.isRootProject) {
|
|
890
|
+
[
|
|
891
|
+
[this.project.preCompileTask, this.preCompileTask],
|
|
892
|
+
[this.project.compileTask, this.compileTask],
|
|
893
|
+
[this.project.postCompileTask, this.postCompileTask],
|
|
894
|
+
[this.project.testTask, this.testTask],
|
|
895
|
+
[this.project.packageTask, this.packageTask]
|
|
896
|
+
].forEach(([pjTask, turboTask]) => {
|
|
897
|
+
if (pjTask && turboTask && pjTask.steps.length > 0) {
|
|
898
|
+
if (nextDependsOn.length > 0) {
|
|
899
|
+
turboTask.dependsOn.push(...nextDependsOn);
|
|
900
|
+
}
|
|
901
|
+
nextDependsOn = [turboTask.name];
|
|
902
|
+
} else {
|
|
903
|
+
turboTask.isActive = false;
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
this.buildTask.dependsOn.push(...nextDependsOn);
|
|
907
|
+
}
|
|
908
|
+
const fileName = "turbo.json";
|
|
909
|
+
this.project.addPackageIgnore(fileName);
|
|
910
|
+
new JsonFile(this.project, fileName, {
|
|
911
|
+
obj: {
|
|
912
|
+
extends: this.extends.length ? this.extends : void 0,
|
|
913
|
+
globalDependencies: this.isRootProject && this.globalDependencies.length ? this.globalDependencies : void 0,
|
|
914
|
+
globalEnv: this.isRootProject && this.globalEnv.length ? this.globalEnv : void 0,
|
|
915
|
+
globalPassThroughEnv: this.isRootProject && this.globalPassThroughEnv.length ? this.globalPassThroughEnv : void 0,
|
|
916
|
+
ui: this.isRootProject ? this.ui : void 0,
|
|
917
|
+
dangerouslyDisablePackageManagerCheck: this.isRootProject ? this.dangerouslyDisablePackageManagerCheck : void 0,
|
|
918
|
+
cacheDir: this.isRootProject ? this.cacheDir : void 0,
|
|
919
|
+
daemon: this.isRootProject ? this.daemon : void 0,
|
|
920
|
+
envMode: this.isRootProject ? this.envMode : void 0,
|
|
921
|
+
/**
|
|
922
|
+
* All tasks
|
|
923
|
+
*/
|
|
924
|
+
tasks: this.tasks.filter((task) => task.isActive).reduce(
|
|
925
|
+
(acc, task) => {
|
|
926
|
+
acc[task.name] = {
|
|
927
|
+
...task.taskConfig()
|
|
928
|
+
};
|
|
929
|
+
return acc;
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
[this.buildTask.name]: { ...this.buildTask.taskConfig() }
|
|
933
|
+
}
|
|
934
|
+
)
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
super.preSynthesize();
|
|
938
|
+
}
|
|
939
|
+
};
|
|
940
|
+
_TurboRepo.buildWorkflowOptions = (remoteCacheOptions) => {
|
|
941
|
+
return {
|
|
942
|
+
env: {
|
|
943
|
+
GIT_BRANCH_NAME: "${{ github.head_ref || github.ref_name }}"
|
|
944
|
+
},
|
|
945
|
+
permissions: {
|
|
946
|
+
contents: JobPermission.WRITE,
|
|
947
|
+
idToken: JobPermission.WRITE
|
|
948
|
+
},
|
|
949
|
+
preBuildSteps: [
|
|
950
|
+
{
|
|
951
|
+
name: "AWS Creds for SSM",
|
|
952
|
+
uses: "aws-actions/configure-aws-credentials@v4",
|
|
953
|
+
with: {
|
|
954
|
+
["role-to-assume"]: remoteCacheOptions.oidcRole,
|
|
955
|
+
["aws-region"]: "us-east-1",
|
|
956
|
+
["role-duration-seconds"]: "900"
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
]
|
|
960
|
+
};
|
|
961
|
+
};
|
|
962
|
+
var TurboRepo = _TurboRepo;
|
|
963
|
+
|
|
964
|
+
// src/agent/bundles/turborepo.ts
|
|
965
|
+
var turborepoBundle = {
|
|
966
|
+
name: "turborepo",
|
|
967
|
+
description: "Turborepo workspace rules and task pipeline conventions",
|
|
968
|
+
appliesWhen: (project) => hasComponent(project, TurboRepo),
|
|
969
|
+
rules: [
|
|
970
|
+
{
|
|
971
|
+
name: "turborepo-conventions",
|
|
972
|
+
description: "Turborepo build system and task pipeline conventions",
|
|
973
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
974
|
+
filePatterns: ["turbo.json", "package.json"],
|
|
975
|
+
content: [
|
|
976
|
+
"# Turborepo Conventions",
|
|
977
|
+
"",
|
|
978
|
+
"## Build System",
|
|
979
|
+
"",
|
|
980
|
+
"- **Build**: `pnpm build:all` (uses Turborepo)",
|
|
981
|
+
"- **Test**: `pnpm test` or `pnpm test:watch`",
|
|
982
|
+
"- **Lint**: `pnpm eslint`",
|
|
983
|
+
"",
|
|
984
|
+
"## Task Pipeline",
|
|
985
|
+
"",
|
|
986
|
+
"- Uses remote caching (requires AWS credentials)",
|
|
987
|
+
"- Only rebuilds changed packages",
|
|
988
|
+
"- Cache key based on file hashes and dependency graph",
|
|
989
|
+
"- Configured in `turbo.json`",
|
|
990
|
+
"",
|
|
991
|
+
"## Workspace Rules",
|
|
992
|
+
"",
|
|
993
|
+
"- Source files: `src/` directory",
|
|
994
|
+
"- Tests: Co-located with source files (`.spec.ts` or `.test.ts`)",
|
|
995
|
+
"- Exports: Use `index.ts` files for clean public APIs",
|
|
996
|
+
"- Configuration: Managed by Projen (edit `.projenrc.ts` or `projenrc/*.ts`)"
|
|
997
|
+
].join("\n"),
|
|
998
|
+
tags: ["workflow"]
|
|
999
|
+
}
|
|
1000
|
+
]
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
// src/agent/bundles/typescript.ts
|
|
1004
|
+
var typescriptBundle = {
|
|
1005
|
+
name: "typescript",
|
|
1006
|
+
description: "TypeScript conventions, type safety, naming, JSDoc, member ordering",
|
|
1007
|
+
appliesWhen: (project) => hasFile(project, "tsconfig.json"),
|
|
1008
|
+
rules: [
|
|
1009
|
+
{
|
|
1010
|
+
name: "typescript-conventions",
|
|
1011
|
+
description: "TypeScript coding conventions and style guide",
|
|
1012
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
1013
|
+
filePatterns: ["**/*.ts", "**/*.tsx"],
|
|
1014
|
+
content: [
|
|
1015
|
+
"# TypeScript Conventions",
|
|
1016
|
+
"",
|
|
1017
|
+
"## Type Safety",
|
|
1018
|
+
"",
|
|
1019
|
+
"- Use **strict TypeScript** with all strict checks enabled",
|
|
1020
|
+
"- Always use explicit types; avoid `any` unless absolutely necessary",
|
|
1021
|
+
"- Use `readonly` for immutable properties",
|
|
1022
|
+
"- Prefer interfaces over types for object shapes",
|
|
1023
|
+
"- Use proper TypeScript types from libraries",
|
|
1024
|
+
"",
|
|
1025
|
+
"## Code Organization",
|
|
1026
|
+
"",
|
|
1027
|
+
"- Follow the member ordering rule:",
|
|
1028
|
+
" 1. Public static fields/methods",
|
|
1029
|
+
" 2. Protected static fields/methods",
|
|
1030
|
+
" 3. Private static fields/methods",
|
|
1031
|
+
" 4. Instance fields",
|
|
1032
|
+
" 5. Constructor",
|
|
1033
|
+
" 6. Methods",
|
|
1034
|
+
"",
|
|
1035
|
+
"## Documentation",
|
|
1036
|
+
"",
|
|
1037
|
+
"- **Keep JSDoc minimal** so that the code remains human-readable. Use brief summaries only.",
|
|
1038
|
+
"- Use JSDoc for:",
|
|
1039
|
+
" - Public classes and interfaces (short description)",
|
|
1040
|
+
" - Public methods and properties (brief purpose; parameter and return when not obvious)",
|
|
1041
|
+
" - Configuration options (one-line description)",
|
|
1042
|
+
"- **Extended documentation** belongs in **markdown** files. Link from JSDoc via `@see` or an inline link.",
|
|
1043
|
+
"",
|
|
1044
|
+
"## Naming Conventions",
|
|
1045
|
+
"",
|
|
1046
|
+
"- **Classes**: PascalCase (e.g., `TypeScriptProject`, `StaticHosting`)",
|
|
1047
|
+
"- **Interfaces**: PascalCase, often with `Props` suffix for configuration (e.g., `StaticHostingProps`)",
|
|
1048
|
+
"- **Functions/Methods**: camelCase (e.g., `configureProject`)",
|
|
1049
|
+
"- **Constants**: UPPER_SNAKE_CASE (e.g., `VERSION`, `AWS_STAGE_TYPE`)",
|
|
1050
|
+
"- **Files**: kebab-case for multi-word files (e.g., `aws-deployment-config.ts`)",
|
|
1051
|
+
"- **Private members**: No prefix needed (TypeScript handles visibility)"
|
|
1052
|
+
].join("\n"),
|
|
1053
|
+
tags: ["coding"]
|
|
1054
|
+
}
|
|
1055
|
+
]
|
|
1056
|
+
};
|
|
1057
|
+
|
|
1058
|
+
// src/vitest/vitest-component.ts
|
|
1059
|
+
import { Component as Component4 } from "projen";
|
|
1060
|
+
import { Jest } from "projen/lib/javascript";
|
|
1061
|
+
import { TextFile } from "projen/lib/textfile";
|
|
1062
|
+
|
|
1063
|
+
// src/versions.ts
|
|
1064
|
+
var VERSION = {
|
|
1065
|
+
/**
|
|
1066
|
+
* CDK CLI for workflows and command line operations.
|
|
1067
|
+
*
|
|
1068
|
+
* CLI and lib are versioned separately, so this is the CLI version.
|
|
1069
|
+
*/
|
|
1070
|
+
AWS_CDK_CLI_VERSION: "2.1117.0",
|
|
1071
|
+
/**
|
|
1072
|
+
* CDK Version to use for construct projects.
|
|
1073
|
+
*
|
|
1074
|
+
* CLI and lib are versioned separately, so this is the lib version.
|
|
1075
|
+
*/
|
|
1076
|
+
AWS_CDK_LIB_VERSION: "2.248.0",
|
|
1077
|
+
/**
|
|
1078
|
+
* Version of the AWS Constructs library to use.
|
|
1079
|
+
*/
|
|
1080
|
+
AWS_CONSTRUCTS_VERSION: "10.6.0",
|
|
1081
|
+
/**
|
|
1082
|
+
* Version of Node.js to use in CI workflows at github actions.
|
|
1083
|
+
*/
|
|
1084
|
+
NODE_WORKFLOWS: "24",
|
|
1085
|
+
/**
|
|
1086
|
+
* Version of PNPM to use in workflows at github actions.
|
|
1087
|
+
*/
|
|
1088
|
+
PNPM_VERSION: "10.33.0",
|
|
1089
|
+
/**
|
|
1090
|
+
* Version of Projen to use.
|
|
1091
|
+
*/
|
|
1092
|
+
PROJEN_VERSION: "0.99.34",
|
|
1093
|
+
/**
|
|
1094
|
+
* What version of the turborepo library should we use?
|
|
1095
|
+
*/
|
|
1096
|
+
TURBO_VERSION: "2.9.4",
|
|
1097
|
+
/**
|
|
1098
|
+
* What version of Vite to use (pnpm override). Pinned to 5.x so Vitest 4.x
|
|
1099
|
+
* can load config (Vite 6+/7+ are ESM-only; see issue #142). Remove override
|
|
1100
|
+
* when moving to ESM-only test setup.
|
|
1101
|
+
*/
|
|
1102
|
+
VITE_VERSION: "5.4.11",
|
|
1103
|
+
/**
|
|
1104
|
+
* What version of Vitest to use when testRunner is 'vitest'.
|
|
1105
|
+
* Pinned to 3.x so it works with Vite 5 (Vitest 4 requires Vite 6). See issue #142.
|
|
1106
|
+
*/
|
|
1107
|
+
VITEST_VERSION: "3.2.4"
|
|
1108
|
+
};
|
|
1109
|
+
|
|
1110
|
+
// src/vitest/vitest-component.ts
|
|
1111
|
+
var Vitest = class _Vitest extends Component4 {
|
|
1112
|
+
constructor(project, options = {}) {
|
|
1113
|
+
super(project);
|
|
1114
|
+
this.project = project;
|
|
1115
|
+
this.configFilePath = options.configFilePath ?? "vitest.config.ts";
|
|
1116
|
+
const config = options.config ?? {};
|
|
1117
|
+
this.include = config.include ?? ["**/*.{test,spec}.?(c|m)[jt]s?(x)"];
|
|
1118
|
+
this.exclude = config.exclude ?? [
|
|
1119
|
+
"**/node_modules/**",
|
|
1120
|
+
"**/dist/**",
|
|
1121
|
+
"**/lib/**",
|
|
1122
|
+
"**/.?*"
|
|
1123
|
+
];
|
|
1124
|
+
this.environment = config.environment ?? "node";
|
|
1125
|
+
this.passWithNoTests = config.passWithNoTests ?? true;
|
|
1126
|
+
this.coverageEnabled = config.coverageEnabled ?? true;
|
|
1127
|
+
this.coverageDirectory = config.coverageDirectory ?? "coverage";
|
|
1128
|
+
this.coverageReporters = config.coverageReporters ?? ["text", "lcov"];
|
|
1129
|
+
this.version = options.vitestVersion ?? VERSION.VITEST_VERSION;
|
|
1130
|
+
project.addDevDeps(`vitest@${this.version}`);
|
|
1131
|
+
if (this.coverageEnabled) {
|
|
1132
|
+
project.addDevDeps(`@vitest/coverage-v8@${this.version}`);
|
|
1133
|
+
}
|
|
1134
|
+
const coveragePath = `/${this.coverageDirectory}/`;
|
|
1135
|
+
project.gitignore.addPatterns(coveragePath);
|
|
1136
|
+
project.npmignore?.exclude(coveragePath);
|
|
1137
|
+
this.addTestTasks();
|
|
1138
|
+
this.synthesizeConfig();
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Find the Vitest component on a project.
|
|
1142
|
+
*/
|
|
1143
|
+
static of(project) {
|
|
1144
|
+
const isVitest = (c) => c instanceof _Vitest;
|
|
1145
|
+
return project.components.find(isVitest);
|
|
1146
|
+
}
|
|
1147
|
+
preSynthesize() {
|
|
1148
|
+
super.preSynthesize();
|
|
1149
|
+
for (const component of this.project.components) {
|
|
1150
|
+
if (component instanceof Jest) {
|
|
1151
|
+
throw new Error("Vitest cannot be used together with Jest");
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
addTestTasks() {
|
|
1156
|
+
this.project.testTask.exec("vitest run --update");
|
|
1157
|
+
if (!this.project.tasks.tryFind("test:watch")) {
|
|
1158
|
+
this.project.addTask("test:watch", {
|
|
1159
|
+
description: "Run tests in watch mode",
|
|
1160
|
+
exec: "vitest watch",
|
|
1161
|
+
receiveArgs: true
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
synthesizeConfig() {
|
|
1166
|
+
this.project.tryRemoveFile(this.configFilePath);
|
|
1167
|
+
new TextFile(this, this.configFilePath, {
|
|
1168
|
+
lines: this.renderConfig()
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
renderConfig() {
|
|
1172
|
+
return [
|
|
1173
|
+
'import { defineConfig } from "vitest/config";',
|
|
1174
|
+
"",
|
|
1175
|
+
"export default defineConfig({",
|
|
1176
|
+
" test: {",
|
|
1177
|
+
` include: ${JSON.stringify(this.include)},`,
|
|
1178
|
+
` exclude: ${JSON.stringify(this.exclude)},`,
|
|
1179
|
+
` environment: "${this.environment}",`,
|
|
1180
|
+
` passWithNoTests: ${this.passWithNoTests},`,
|
|
1181
|
+
" coverage: {",
|
|
1182
|
+
` enabled: ${this.coverageEnabled},`,
|
|
1183
|
+
` provider: "v8",`,
|
|
1184
|
+
` reportsDirectory: "${this.coverageDirectory}",`,
|
|
1185
|
+
` reporter: ${JSON.stringify(this.coverageReporters)},`,
|
|
1186
|
+
" },",
|
|
1187
|
+
" },",
|
|
1188
|
+
"});"
|
|
1189
|
+
];
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1192
|
+
|
|
1193
|
+
// src/agent/bundles/vitest.ts
|
|
1194
|
+
var vitestBundle = {
|
|
1195
|
+
name: "vitest",
|
|
1196
|
+
description: "Vitest testing conventions, patterns, and file scoping",
|
|
1197
|
+
appliesWhen: (project) => hasComponent(project, Vitest),
|
|
1198
|
+
rules: [
|
|
1199
|
+
{
|
|
1200
|
+
name: "vitest-testing",
|
|
1201
|
+
description: "Vitest testing conventions and patterns",
|
|
1202
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
1203
|
+
filePatterns: ["**/*.test.ts", "**/*.spec.ts"],
|
|
1204
|
+
content: [
|
|
1205
|
+
"# Vitest Testing Patterns",
|
|
1206
|
+
"",
|
|
1207
|
+
"## Mandatory Requirements",
|
|
1208
|
+
"",
|
|
1209
|
+
"- **Tests MUST be created or updated whenever code functionality is added or changed**",
|
|
1210
|
+
"- This applies to all code changes, including:",
|
|
1211
|
+
" - New features and functionality",
|
|
1212
|
+
" - Bug fixes",
|
|
1213
|
+
" - Refactoring that changes behavior",
|
|
1214
|
+
" - API changes",
|
|
1215
|
+
" - Configuration changes that affect functionality",
|
|
1216
|
+
"- Tests should be written or updated as part of the same change that modifies the code",
|
|
1217
|
+
"",
|
|
1218
|
+
"## Test Structure",
|
|
1219
|
+
"",
|
|
1220
|
+
"- Use **Vitest** as the test runner",
|
|
1221
|
+
"- Test files: `.spec.ts` or `.test.ts` (co-located with source)",
|
|
1222
|
+
"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`",
|
|
1223
|
+
"- Prefer snapshot tests for complex object structures",
|
|
1224
|
+
"- Mock external dependencies appropriately",
|
|
1225
|
+
"",
|
|
1226
|
+
"## Test Organization",
|
|
1227
|
+
"",
|
|
1228
|
+
"- Co-locate test files with source files",
|
|
1229
|
+
"- Test files can use dev dependencies (ESLint rule override)",
|
|
1230
|
+
"- Import from `vitest`: `import { describe, expect, it } from 'vitest'`",
|
|
1231
|
+
"",
|
|
1232
|
+
"## Example Test Structure",
|
|
1233
|
+
"",
|
|
1234
|
+
"```typescript",
|
|
1235
|
+
"import { describe, expect, it } from 'vitest';",
|
|
1236
|
+
"import { MyClass } from './my-class';",
|
|
1237
|
+
"",
|
|
1238
|
+
"describe('MyClass', () => {",
|
|
1239
|
+
" it('should do something specific', () => {",
|
|
1240
|
+
" // Test implementation",
|
|
1241
|
+
" });",
|
|
1242
|
+
"});",
|
|
1243
|
+
"```"
|
|
1244
|
+
].join("\n"),
|
|
1245
|
+
tags: ["testing"]
|
|
1246
|
+
}
|
|
1247
|
+
]
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
// src/agent/bundles/index.ts
|
|
1251
|
+
var BUILT_IN_BUNDLES = [
|
|
1252
|
+
baseBundle,
|
|
1253
|
+
typescriptBundle,
|
|
1254
|
+
vitestBundle,
|
|
1255
|
+
jestBundle,
|
|
1256
|
+
turborepoBundle,
|
|
1257
|
+
pnpmBundle,
|
|
1258
|
+
awsCdkBundle,
|
|
1259
|
+
projenBundle
|
|
1260
|
+
];
|
|
1261
|
+
|
|
1262
|
+
// src/projects/project-metadata.ts
|
|
1263
|
+
import { Component as Component5 } from "projen";
|
|
1264
|
+
import { NodeProject as NodeProject2 } from "projen/lib/javascript";
|
|
1265
|
+
var GITHUB_HTTPS_RE = /(?:https?:\/\/|git\+https:\/\/)github\.com\/([^/]+)\/([^/.]+)(?:\.git)?/;
|
|
1266
|
+
var GITHUB_SSH_RE = /git@github\.com:([^/]+)\/([^/.]+)(?:\.git)?/;
|
|
1267
|
+
function parseGitHubUrl(url) {
|
|
1268
|
+
const httpsMatch = url.match(GITHUB_HTTPS_RE);
|
|
1269
|
+
if (httpsMatch) {
|
|
1270
|
+
return { owner: httpsMatch[1], name: httpsMatch[2] };
|
|
1271
|
+
}
|
|
1272
|
+
const sshMatch = url.match(GITHUB_SSH_RE);
|
|
1273
|
+
if (sshMatch) {
|
|
1274
|
+
return { owner: sshMatch[1], name: sshMatch[2] };
|
|
1275
|
+
}
|
|
1276
|
+
return { owner: void 0, name: void 0 };
|
|
1277
|
+
}
|
|
1278
|
+
var ProjectMetadata = class _ProjectMetadata extends Component5 {
|
|
1279
|
+
/**
|
|
1280
|
+
* Returns the ProjectMetadata instance for a project, or undefined
|
|
1281
|
+
* if the component has not been added.
|
|
1282
|
+
*/
|
|
1283
|
+
static of(project) {
|
|
1284
|
+
const isProjectMetadata = (c) => c instanceof _ProjectMetadata;
|
|
1285
|
+
return project.components.find(isProjectMetadata);
|
|
1286
|
+
}
|
|
1287
|
+
constructor(project, options = {}) {
|
|
1288
|
+
super(project);
|
|
1289
|
+
this.metadata = this.resolveMetadata(options);
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Merges explicit options with auto-detected values.
|
|
1293
|
+
* Auto-detection reads the repository URL from package.json
|
|
1294
|
+
* (via Projen's NodePackage manifest) and parses GitHub owner/name.
|
|
1295
|
+
* Explicit options always take precedence over auto-detected values.
|
|
1296
|
+
*/
|
|
1297
|
+
resolveMetadata(options) {
|
|
1298
|
+
const autoDetected = this.autoDetectRepository();
|
|
1299
|
+
return {
|
|
1300
|
+
repository: {
|
|
1301
|
+
owner: options.repository?.owner ?? autoDetected.owner,
|
|
1302
|
+
name: options.repository?.name ?? autoDetected.name,
|
|
1303
|
+
defaultBranch: options.repository?.defaultBranch ?? "main"
|
|
1304
|
+
},
|
|
1305
|
+
githubProject: options.githubProject,
|
|
1306
|
+
organization: options.organization,
|
|
1307
|
+
slack: options.slack,
|
|
1308
|
+
labels: options.labels,
|
|
1309
|
+
milestones: options.milestones,
|
|
1310
|
+
docsPath: options.docsPath,
|
|
1311
|
+
deployment: options.deployment
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Attempts to auto-detect repository owner and name from the Projen
|
|
1316
|
+
* project's package.json repository field.
|
|
1317
|
+
*/
|
|
1318
|
+
autoDetectRepository() {
|
|
1319
|
+
if (!(this.project instanceof NodeProject2)) {
|
|
1320
|
+
return { owner: void 0, name: void 0 };
|
|
1321
|
+
}
|
|
1322
|
+
const manifest = this.project.package.manifest;
|
|
1323
|
+
const repoField = manifest.repository;
|
|
1324
|
+
if (!repoField) {
|
|
1325
|
+
return { owner: void 0, name: void 0 };
|
|
1326
|
+
}
|
|
1327
|
+
const url = typeof repoField === "string" ? repoField : repoField.url ?? "";
|
|
1328
|
+
return parseGitHubUrl(url);
|
|
1329
|
+
}
|
|
1330
|
+
};
|
|
1331
|
+
|
|
213
1332
|
// src/agent/renderers/claude-renderer.ts
|
|
1333
|
+
import { JsonFile as JsonFile2 } from "projen";
|
|
1334
|
+
import { TextFile as TextFile2 } from "projen/lib/textfile";
|
|
214
1335
|
var GENERATED_MARKER = "<!-- ~~ Generated by @codedrifters/configulator. Edits welcome \u2014 please contribute improvements back. ~~ -->";
|
|
215
1336
|
var ClaudeRenderer = class _ClaudeRenderer {
|
|
216
1337
|
/**
|
|
@@ -235,7 +1356,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
235
1356
|
if (i > 0) lines.push("", "---", "");
|
|
236
1357
|
lines.push(...claudeMdRules[i].content.split("\n"));
|
|
237
1358
|
}
|
|
238
|
-
new
|
|
1359
|
+
new TextFile2(component, "CLAUDE.md", { lines });
|
|
239
1360
|
}
|
|
240
1361
|
static renderScopedRules(component, rules) {
|
|
241
1362
|
const scopedRules = rules.filter((r) => {
|
|
@@ -255,7 +1376,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
255
1376
|
lines.push("");
|
|
256
1377
|
}
|
|
257
1378
|
lines.push(...rule.content.split("\n"));
|
|
258
|
-
new
|
|
1379
|
+
new TextFile2(component, `.claude/rules/${rule.name}.md`, { lines });
|
|
259
1380
|
}
|
|
260
1381
|
}
|
|
261
1382
|
static renderSettings(component, mcpServers, settings) {
|
|
@@ -370,7 +1491,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
370
1491
|
hasContent = true;
|
|
371
1492
|
}
|
|
372
1493
|
if (!hasContent) return;
|
|
373
|
-
new
|
|
1494
|
+
new JsonFile2(component, ".claude/settings.json", { obj });
|
|
374
1495
|
}
|
|
375
1496
|
static buildSandboxObj(sandbox) {
|
|
376
1497
|
const obj = {};
|
|
@@ -446,7 +1567,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
446
1567
|
lines.push("---");
|
|
447
1568
|
lines.push("");
|
|
448
1569
|
lines.push(...skill.instructions.split("\n"));
|
|
449
|
-
new
|
|
1570
|
+
new TextFile2(component, `.claude/skills/${skill.name}/SKILL.md`, {
|
|
450
1571
|
lines
|
|
451
1572
|
});
|
|
452
1573
|
}
|
|
@@ -483,7 +1604,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
483
1604
|
lines.push("---");
|
|
484
1605
|
lines.push("");
|
|
485
1606
|
lines.push(...agent.prompt.split("\n"));
|
|
486
|
-
new
|
|
1607
|
+
new TextFile2(component, `.claude/agents/${agent.name}.md`, { lines });
|
|
487
1608
|
}
|
|
488
1609
|
}
|
|
489
1610
|
/**
|
|
@@ -508,8 +1629,8 @@ var CopilotRenderer = class {
|
|
|
508
1629
|
};
|
|
509
1630
|
|
|
510
1631
|
// src/agent/renderers/cursor-renderer.ts
|
|
511
|
-
import { JsonFile as
|
|
512
|
-
import { TextFile as
|
|
1632
|
+
import { JsonFile as JsonFile3 } from "projen";
|
|
1633
|
+
import { TextFile as TextFile3 } from "projen/lib/textfile";
|
|
513
1634
|
var GENERATED_MARKER2 = "# ~~ Generated by @codedrifters/configulator. Edits welcome \u2014 please contribute improvements back. ~~";
|
|
514
1635
|
var CursorRenderer = class _CursorRenderer {
|
|
515
1636
|
/**
|
|
@@ -538,7 +1659,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
538
1659
|
lines.push("---");
|
|
539
1660
|
lines.push("");
|
|
540
1661
|
lines.push(...rule.content.split("\n"));
|
|
541
|
-
new
|
|
1662
|
+
new TextFile3(component, `.cursor/rules/${rule.name}.mdc`, { lines });
|
|
542
1663
|
}
|
|
543
1664
|
}
|
|
544
1665
|
static renderSkills(component, skills) {
|
|
@@ -562,7 +1683,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
562
1683
|
lines.push("---");
|
|
563
1684
|
lines.push("");
|
|
564
1685
|
lines.push(...skill.instructions.split("\n"));
|
|
565
|
-
new
|
|
1686
|
+
new TextFile3(component, `.cursor/skills/${skill.name}/SKILL.md`, {
|
|
566
1687
|
lines
|
|
567
1688
|
});
|
|
568
1689
|
}
|
|
@@ -587,7 +1708,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
587
1708
|
lines.push("---");
|
|
588
1709
|
lines.push("");
|
|
589
1710
|
lines.push(...agent.prompt.split("\n"));
|
|
590
|
-
new
|
|
1711
|
+
new TextFile3(component, `.cursor/agents/${agent.name}.md`, { lines });
|
|
591
1712
|
}
|
|
592
1713
|
}
|
|
593
1714
|
static renderMcpServers(component, mcpServers) {
|
|
@@ -603,7 +1724,7 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
603
1724
|
if (config.env) server.env = { ...config.env };
|
|
604
1725
|
servers[name] = server;
|
|
605
1726
|
}
|
|
606
|
-
new
|
|
1727
|
+
new JsonFile3(component, ".cursor/mcp.json", { obj });
|
|
607
1728
|
}
|
|
608
1729
|
static renderHooks(component, settings) {
|
|
609
1730
|
if (!settings?.hooks) return;
|
|
@@ -641,26 +1762,75 @@ var CursorRenderer = class _CursorRenderer {
|
|
|
641
1762
|
}
|
|
642
1763
|
if (stop?.length) hooks.stop = stop.map((h) => ({ command: h.command }));
|
|
643
1764
|
if (Object.keys(hooks).length === 0) return;
|
|
644
|
-
new
|
|
1765
|
+
new JsonFile3(component, ".cursor/hooks.json", {
|
|
645
1766
|
obj: { version: 1, hooks }
|
|
646
1767
|
});
|
|
647
1768
|
}
|
|
648
1769
|
static renderIgnoreFiles(component, settings) {
|
|
649
1770
|
if (settings?.ignorePatterns && settings.ignorePatterns.length > 0) {
|
|
650
|
-
new
|
|
1771
|
+
new TextFile3(component, ".cursorignore", {
|
|
651
1772
|
lines: [GENERATED_MARKER2, "", ...settings.ignorePatterns]
|
|
652
1773
|
});
|
|
653
1774
|
}
|
|
654
1775
|
if (settings?.indexingIgnorePatterns && settings.indexingIgnorePatterns.length > 0) {
|
|
655
|
-
new
|
|
1776
|
+
new TextFile3(component, ".cursorindexingignore", {
|
|
656
1777
|
lines: [GENERATED_MARKER2, "", ...settings.indexingIgnorePatterns]
|
|
657
1778
|
});
|
|
658
1779
|
}
|
|
659
1780
|
}
|
|
660
1781
|
};
|
|
661
1782
|
|
|
1783
|
+
// src/agent/template-resolver.ts
|
|
1784
|
+
var FALLBACKS = {
|
|
1785
|
+
"repository.owner": "<owner>",
|
|
1786
|
+
"repository.name": "<repo>",
|
|
1787
|
+
"repository.defaultBranch": "main",
|
|
1788
|
+
"organization.name": "<organization>",
|
|
1789
|
+
"organization.githubOrg": "<org>",
|
|
1790
|
+
"githubProject.name": "<project-name>",
|
|
1791
|
+
"githubProject.number": "<project-number>",
|
|
1792
|
+
"githubProject.nodeId": "<project-node-id>",
|
|
1793
|
+
docsPath: "<docs-path>"
|
|
1794
|
+
};
|
|
1795
|
+
var TEMPLATE_RE = /\{\{(\w+(?:\.\w+)*)\}\}/g;
|
|
1796
|
+
function getNestedValue(obj, path) {
|
|
1797
|
+
const parts = path.split(".");
|
|
1798
|
+
let current = obj;
|
|
1799
|
+
for (const part of parts) {
|
|
1800
|
+
if (current == null || typeof current !== "object") {
|
|
1801
|
+
return void 0;
|
|
1802
|
+
}
|
|
1803
|
+
current = current[part];
|
|
1804
|
+
}
|
|
1805
|
+
if (current == null) {
|
|
1806
|
+
return void 0;
|
|
1807
|
+
}
|
|
1808
|
+
return String(current);
|
|
1809
|
+
}
|
|
1810
|
+
function resolveTemplateVariables(template, metadata) {
|
|
1811
|
+
if (!TEMPLATE_RE.test(template)) {
|
|
1812
|
+
return { resolved: template, unresolvedKeys: [] };
|
|
1813
|
+
}
|
|
1814
|
+
const unresolvedKeys = [];
|
|
1815
|
+
TEMPLATE_RE.lastIndex = 0;
|
|
1816
|
+
const resolved = template.replace(TEMPLATE_RE, (_match, key) => {
|
|
1817
|
+
if (metadata) {
|
|
1818
|
+
const value = getNestedValue(
|
|
1819
|
+
metadata,
|
|
1820
|
+
key
|
|
1821
|
+
);
|
|
1822
|
+
if (value !== void 0) {
|
|
1823
|
+
return value;
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
unresolvedKeys.push(key);
|
|
1827
|
+
return FALLBACKS[key] ?? `<${key}>`;
|
|
1828
|
+
});
|
|
1829
|
+
return { resolved, unresolvedKeys };
|
|
1830
|
+
}
|
|
1831
|
+
|
|
662
1832
|
// src/agent/agent-config.ts
|
|
663
|
-
var AgentConfig = class _AgentConfig extends
|
|
1833
|
+
var AgentConfig = class _AgentConfig extends Component8 {
|
|
664
1834
|
/**
|
|
665
1835
|
* Find the AgentConfig component on a project.
|
|
666
1836
|
*/
|
|
@@ -679,12 +1849,20 @@ var AgentConfig = class _AgentConfig extends Component3 {
|
|
|
679
1849
|
const skills = this.resolveSkills();
|
|
680
1850
|
const subAgents = this.resolveSubAgents();
|
|
681
1851
|
const mcpServers = this.options.mcpServers ?? {};
|
|
1852
|
+
const projectMetadata = ProjectMetadata.of(this.project);
|
|
1853
|
+
const metadata = projectMetadata?.metadata;
|
|
1854
|
+
const resolvedRules = this.resolveTemplates(rules, metadata);
|
|
1855
|
+
const resolvedSkills = this.resolveSkillTemplates(skills, metadata);
|
|
1856
|
+
const resolvedSubAgents = this.resolveSubAgentTemplates(
|
|
1857
|
+
subAgents,
|
|
1858
|
+
metadata
|
|
1859
|
+
);
|
|
682
1860
|
if (platforms.includes(AGENT_PLATFORM.CURSOR)) {
|
|
683
1861
|
CursorRenderer.render(
|
|
684
1862
|
this,
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
1863
|
+
resolvedRules,
|
|
1864
|
+
resolvedSkills,
|
|
1865
|
+
resolvedSubAgents,
|
|
688
1866
|
mcpServers,
|
|
689
1867
|
this.options.cursorSettings
|
|
690
1868
|
);
|
|
@@ -692,18 +1870,28 @@ var AgentConfig = class _AgentConfig extends Component3 {
|
|
|
692
1870
|
if (platforms.includes(AGENT_PLATFORM.CLAUDE)) {
|
|
693
1871
|
ClaudeRenderer.render(
|
|
694
1872
|
this,
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
1873
|
+
resolvedRules,
|
|
1874
|
+
resolvedSkills,
|
|
1875
|
+
resolvedSubAgents,
|
|
698
1876
|
mcpServers,
|
|
699
1877
|
this.options.claudeSettings
|
|
700
1878
|
);
|
|
701
1879
|
}
|
|
702
1880
|
if (platforms.includes(AGENT_PLATFORM.CODEX)) {
|
|
703
|
-
CodexRenderer.render(
|
|
1881
|
+
CodexRenderer.render(
|
|
1882
|
+
this,
|
|
1883
|
+
resolvedRules,
|
|
1884
|
+
resolvedSkills,
|
|
1885
|
+
resolvedSubAgents
|
|
1886
|
+
);
|
|
704
1887
|
}
|
|
705
1888
|
if (platforms.includes(AGENT_PLATFORM.COPILOT)) {
|
|
706
|
-
CopilotRenderer.render(
|
|
1889
|
+
CopilotRenderer.render(
|
|
1890
|
+
this,
|
|
1891
|
+
resolvedRules,
|
|
1892
|
+
resolvedSkills,
|
|
1893
|
+
resolvedSubAgents
|
|
1894
|
+
);
|
|
707
1895
|
}
|
|
708
1896
|
}
|
|
709
1897
|
resolvePlatforms() {
|
|
@@ -714,6 +1902,9 @@ var AgentConfig = class _AgentConfig extends Component3 {
|
|
|
714
1902
|
if (this.options.autoDetectBundles !== false) {
|
|
715
1903
|
for (const bundle of BUILT_IN_BUNDLES) {
|
|
716
1904
|
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
1905
|
+
if (bundle.name === "base" && this.options.includeBaseRules === false) {
|
|
1906
|
+
continue;
|
|
1907
|
+
}
|
|
717
1908
|
if (bundle.appliesWhen(this.project)) {
|
|
718
1909
|
for (const rule of bundle.rules) {
|
|
719
1910
|
ruleMap.set(rule.name, rule);
|
|
@@ -741,6 +1932,21 @@ var AgentConfig = class _AgentConfig extends Component3 {
|
|
|
741
1932
|
ruleMap.delete(name);
|
|
742
1933
|
}
|
|
743
1934
|
}
|
|
1935
|
+
if (this.options.ruleExtensions) {
|
|
1936
|
+
for (const [name, extra] of Object.entries(this.options.ruleExtensions)) {
|
|
1937
|
+
const existing = ruleMap.get(name);
|
|
1938
|
+
if (existing) {
|
|
1939
|
+
ruleMap.set(name, {
|
|
1940
|
+
...existing,
|
|
1941
|
+
content: `${existing.content}
|
|
1942
|
+
|
|
1943
|
+
---
|
|
1944
|
+
|
|
1945
|
+
${extra}`
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
744
1950
|
return [...ruleMap.values()].sort((a, b) => {
|
|
745
1951
|
if (a.name === "project-overview") return -1;
|
|
746
1952
|
if (b.name === "project-overview") return 1;
|
|
@@ -788,264 +1994,65 @@ var AgentConfig = class _AgentConfig extends Component3 {
|
|
|
788
1994
|
}
|
|
789
1995
|
return [...agentMap.values()];
|
|
790
1996
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
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
|
-
)
|
|
1997
|
+
/**
|
|
1998
|
+
* Resolves template variables in rule content using project metadata.
|
|
1999
|
+
* Emits synthesis warnings for rules with unresolved variables.
|
|
2000
|
+
*/
|
|
2001
|
+
resolveTemplates(rules, metadata) {
|
|
2002
|
+
return rules.map((rule) => {
|
|
2003
|
+
const { resolved, unresolvedKeys } = resolveTemplateVariables(
|
|
2004
|
+
rule.content,
|
|
2005
|
+
metadata
|
|
2006
|
+
);
|
|
2007
|
+
if (unresolvedKeys.length > 0) {
|
|
2008
|
+
this.project.logger.warn(
|
|
2009
|
+
`AgentConfig: ProjectMetadata not found; rule '${rule.name}' using default values`
|
|
2010
|
+
);
|
|
1018
2011
|
}
|
|
2012
|
+
return resolved !== rule.content ? { ...rule, content: resolved } : rule;
|
|
1019
2013
|
});
|
|
1020
|
-
super.preSynthesize();
|
|
1021
2014
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
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"
|
|
1040
|
-
}
|
|
2015
|
+
/**
|
|
2016
|
+
* Resolves template variables in skill instructions using project metadata.
|
|
2017
|
+
*/
|
|
2018
|
+
resolveSkillTemplates(skills, metadata) {
|
|
2019
|
+
return skills.map((skill) => {
|
|
2020
|
+
const { resolved, unresolvedKeys } = resolveTemplateVariables(
|
|
2021
|
+
skill.instructions,
|
|
2022
|
+
metadata
|
|
2023
|
+
);
|
|
2024
|
+
if (unresolvedKeys.length > 0) {
|
|
2025
|
+
this.project.logger.warn(
|
|
2026
|
+
`AgentConfig: ProjectMetadata not found; skill '${skill.name}' using default values`
|
|
2027
|
+
);
|
|
1041
2028
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
2029
|
+
return resolved !== skill.instructions ? { ...skill, instructions: resolved } : skill;
|
|
2030
|
+
});
|
|
2031
|
+
}
|
|
2032
|
+
/**
|
|
2033
|
+
* Resolves template variables in sub-agent prompts using project metadata.
|
|
2034
|
+
*/
|
|
2035
|
+
resolveSubAgentTemplates(subAgents, metadata) {
|
|
2036
|
+
return subAgents.map((agent) => {
|
|
2037
|
+
const { resolved, unresolvedKeys } = resolveTemplateVariables(
|
|
2038
|
+
agent.prompt,
|
|
2039
|
+
metadata
|
|
2040
|
+
);
|
|
2041
|
+
if (unresolvedKeys.length > 0) {
|
|
2042
|
+
this.project.logger.warn(
|
|
2043
|
+
`AgentConfig: ProjectMetadata not found; sub-agent '${agent.name}' using default values`
|
|
2044
|
+
);
|
|
2045
|
+
}
|
|
2046
|
+
return resolved !== agent.prompt ? { ...agent, prompt: resolved } : agent;
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
1044
2049
|
};
|
|
1045
|
-
var TurboRepo = _TurboRepo;
|
|
1046
2050
|
|
|
1047
2051
|
// src/aws/aws-deployment-config.ts
|
|
1048
|
-
var
|
|
2052
|
+
var import_utils8 = __toESM(require_lib());
|
|
2053
|
+
import { join, relative as relative2 } from "path";
|
|
2054
|
+
import { Component as Component9 } from "projen";
|
|
2055
|
+
var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component9 {
|
|
1049
2056
|
constructor(project) {
|
|
1050
2057
|
super(project);
|
|
1051
2058
|
/**
|
|
@@ -1069,8 +2076,8 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component6 {
|
|
|
1069
2076
|
this.env = {
|
|
1070
2077
|
GIT_BRANCH_NAME: '$(echo "${GIT_BRANCH_NAME:-$(git branch --show-current)}")'
|
|
1071
2078
|
};
|
|
1072
|
-
this.projectPath =
|
|
1073
|
-
this.rootPath =
|
|
2079
|
+
this.projectPath = relative2(project.root.outdir, project.outdir);
|
|
2080
|
+
this.rootPath = relative2(project.outdir, project.root.outdir);
|
|
1074
2081
|
this.rootCdkOut = join("dist", this.projectPath, "cdk.out");
|
|
1075
2082
|
this.cdkOut = join(this.rootPath, "dist", this.projectPath, "cdk.out");
|
|
1076
2083
|
["deploy", "watch"].forEach((taskName) => {
|
|
@@ -1100,17 +2107,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component6 {
|
|
|
1100
2107
|
*/
|
|
1101
2108
|
get prodTargets() {
|
|
1102
2109
|
return this.awsDeploymentTargets.filter(
|
|
1103
|
-
(target) => target.awsStageType ===
|
|
2110
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD
|
|
1104
2111
|
);
|
|
1105
2112
|
}
|
|
1106
2113
|
get prodTargetsForCI() {
|
|
1107
2114
|
return this.awsDeploymentTargets.filter(
|
|
1108
|
-
(target) => target.awsStageType ===
|
|
2115
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD && target.ciDeployment
|
|
1109
2116
|
);
|
|
1110
2117
|
}
|
|
1111
2118
|
get prodTargetsForLocal() {
|
|
1112
2119
|
return this.awsDeploymentTargets.filter(
|
|
1113
|
-
(target) => target.awsStageType ===
|
|
2120
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.PROD && target.localDeployment
|
|
1114
2121
|
);
|
|
1115
2122
|
}
|
|
1116
2123
|
/**
|
|
@@ -1119,17 +2126,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component6 {
|
|
|
1119
2126
|
*/
|
|
1120
2127
|
get stageTargets() {
|
|
1121
2128
|
return this.awsDeploymentTargets.filter(
|
|
1122
|
-
(target) => target.awsStageType ===
|
|
2129
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE
|
|
1123
2130
|
);
|
|
1124
2131
|
}
|
|
1125
2132
|
get stageTargetsForCI() {
|
|
1126
2133
|
return this.awsDeploymentTargets.filter(
|
|
1127
|
-
(target) => target.awsStageType ===
|
|
2134
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE && target.ciDeployment
|
|
1128
2135
|
);
|
|
1129
2136
|
}
|
|
1130
2137
|
get stageTargetsForLocal() {
|
|
1131
2138
|
return this.awsDeploymentTargets.filter(
|
|
1132
|
-
(target) => target.awsStageType ===
|
|
2139
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.STAGE && target.localDeployment
|
|
1133
2140
|
);
|
|
1134
2141
|
}
|
|
1135
2142
|
/**
|
|
@@ -1138,17 +2145,17 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component6 {
|
|
|
1138
2145
|
*/
|
|
1139
2146
|
get devTargets() {
|
|
1140
2147
|
return this.awsDeploymentTargets.filter(
|
|
1141
|
-
(target) => target.awsStageType ===
|
|
2148
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV
|
|
1142
2149
|
);
|
|
1143
2150
|
}
|
|
1144
2151
|
get devTargetsForCI() {
|
|
1145
2152
|
return this.awsDeploymentTargets.filter(
|
|
1146
|
-
(target) => target.awsStageType ===
|
|
2153
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV && target.ciDeployment
|
|
1147
2154
|
);
|
|
1148
2155
|
}
|
|
1149
2156
|
get devTargetsForLocal() {
|
|
1150
2157
|
return this.awsDeploymentTargets.filter(
|
|
1151
|
-
(target) => target.awsStageType ===
|
|
2158
|
+
(target) => target.awsStageType === import_utils8.AWS_STAGE_TYPE.DEV && target.localDeployment
|
|
1152
2159
|
);
|
|
1153
2160
|
}
|
|
1154
2161
|
preSynthesize() {
|
|
@@ -1161,9 +2168,9 @@ var AwsDeploymentConfig = class _AwsDeploymentConfig extends Component6 {
|
|
|
1161
2168
|
};
|
|
1162
2169
|
|
|
1163
2170
|
// src/aws/aws-deployment-target.ts
|
|
1164
|
-
var
|
|
1165
|
-
import { Component as
|
|
1166
|
-
var AwsDeploymentTarget = class _AwsDeploymentTarget extends
|
|
2171
|
+
var import_utils9 = __toESM(require_lib());
|
|
2172
|
+
import { Component as Component10 } from "projen";
|
|
2173
|
+
var AwsDeploymentTarget = class _AwsDeploymentTarget extends Component10 {
|
|
1167
2174
|
constructor(project, options) {
|
|
1168
2175
|
super(project);
|
|
1169
2176
|
/**
|
|
@@ -1228,11 +2235,11 @@ var AwsDeploymentTarget = class _AwsDeploymentTarget extends Component7 {
|
|
|
1228
2235
|
};
|
|
1229
2236
|
this.account = options.account;
|
|
1230
2237
|
this.region = options.region;
|
|
1231
|
-
this.awsStageType = options.awsStageType ||
|
|
1232
|
-
const role = options.deploymentTargetRole ?? options.awsEnvironmentType ??
|
|
2238
|
+
this.awsStageType = options.awsStageType || import_utils9.AWS_STAGE_TYPE.DEV;
|
|
2239
|
+
const role = options.deploymentTargetRole ?? options.awsEnvironmentType ?? import_utils9.DEPLOYMENT_TARGET_ROLE.PRIMARY;
|
|
1233
2240
|
this.deploymentTargetRole = role;
|
|
1234
2241
|
this.awsEnvironmentType = role;
|
|
1235
|
-
this.branches = options.branches ?? (this.awsStageType ===
|
|
2242
|
+
this.branches = options.branches ?? (this.awsStageType === import_utils9.AWS_STAGE_TYPE.PROD ? [
|
|
1236
2243
|
{
|
|
1237
2244
|
branch: "main"
|
|
1238
2245
|
}
|
|
@@ -1241,7 +2248,7 @@ var AwsDeploymentTarget = class _AwsDeploymentTarget extends Component7 {
|
|
|
1241
2248
|
branch: "feature/*"
|
|
1242
2249
|
}
|
|
1243
2250
|
]);
|
|
1244
|
-
this.localDeployment = options.localDeployment ?? this.awsStageType ===
|
|
2251
|
+
this.localDeployment = options.localDeployment ?? this.awsStageType === import_utils9.AWS_STAGE_TYPE.DEV;
|
|
1245
2252
|
if (this.localDeployment) {
|
|
1246
2253
|
const roleName = options.localDeploymentConfig?.roleName?.toLowerCase() || "poweruseraccess";
|
|
1247
2254
|
const profile = options.localDeploymentConfig?.profile || `${roleName}-${this.awsStageType}-${this.account}-${this.region}`;
|
|
@@ -1376,61 +2383,14 @@ var VERSION_KEYS_SKIP = [
|
|
|
1376
2383
|
// Pinned to 3.x for Vite 5 compatibility; skip until ESM-only (issue #142)
|
|
1377
2384
|
];
|
|
1378
2385
|
|
|
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
2386
|
// src/jsii/jsii-faker.ts
|
|
1427
2387
|
import * as spec from "@jsii/spec";
|
|
1428
|
-
import { Component as
|
|
2388
|
+
import { Component as Component11, JsonFile as JsonFile4 } from "projen";
|
|
1429
2389
|
var ProjenBaseFqn = {
|
|
1430
2390
|
TYPESCRIPT_PROJECT: "projen.typescript.TypeScriptProject",
|
|
1431
2391
|
TYPESCRIPT_PROJECT_OPTIONS: "projen.typescript.TypeScriptProjectOptions"
|
|
1432
2392
|
};
|
|
1433
|
-
var JsiiFaker = class _JsiiFaker extends
|
|
2393
|
+
var JsiiFaker = class _JsiiFaker extends Component11 {
|
|
1434
2394
|
constructor(project) {
|
|
1435
2395
|
super(project);
|
|
1436
2396
|
this.project = project;
|
|
@@ -1478,86 +2438,6 @@ var JsiiFaker = class _JsiiFaker extends Component8 {
|
|
|
1478
2438
|
}
|
|
1479
2439
|
};
|
|
1480
2440
|
|
|
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
2441
|
// src/projects/monorepo-project.ts
|
|
1562
2442
|
import {
|
|
1563
2443
|
NodePackageManager as NodePackageManager2,
|
|
@@ -1569,7 +2449,7 @@ import {
|
|
|
1569
2449
|
import { merge as merge2 } from "ts-deepmerge";
|
|
1570
2450
|
|
|
1571
2451
|
// src/tasks/reset-task.ts
|
|
1572
|
-
import { Component as
|
|
2452
|
+
import { Component as Component12 } from "projen";
|
|
1573
2453
|
|
|
1574
2454
|
// src/projects/typescript-project.ts
|
|
1575
2455
|
import { typescript } from "projen";
|
|
@@ -1580,94 +2460,6 @@ import {
|
|
|
1580
2460
|
} from "projen/lib/javascript";
|
|
1581
2461
|
import { ReleaseTrigger } from "projen/lib/release";
|
|
1582
2462
|
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
2463
|
var TestRunner = {
|
|
1672
2464
|
JEST: "jest",
|
|
1673
2465
|
VITEST: "vitest"
|
|
@@ -1832,7 +2624,7 @@ var TypeScriptProject = class extends typescript.TypeScriptProject {
|
|
|
1832
2624
|
};
|
|
1833
2625
|
|
|
1834
2626
|
// src/tasks/reset-task.ts
|
|
1835
|
-
var ResetTask = class _ResetTask extends
|
|
2627
|
+
var ResetTask = class _ResetTask extends Component12 {
|
|
1836
2628
|
constructor(project, options = {}) {
|
|
1837
2629
|
super(project);
|
|
1838
2630
|
this.project = project;
|
|
@@ -1905,8 +2697,8 @@ var ResetTask = class _ResetTask extends Component11 {
|
|
|
1905
2697
|
};
|
|
1906
2698
|
|
|
1907
2699
|
// src/vscode/vscode.ts
|
|
1908
|
-
import { Component as
|
|
1909
|
-
var VSCodeConfig = class extends
|
|
2700
|
+
import { Component as Component13, vscode } from "projen";
|
|
2701
|
+
var VSCodeConfig = class extends Component13 {
|
|
1910
2702
|
constructor(project) {
|
|
1911
2703
|
super(project);
|
|
1912
2704
|
const vsConfig = new vscode.VsCode(project);
|
|
@@ -2282,6 +3074,15 @@ var MonorepoProject = class extends TypeScriptAppProject {
|
|
|
2282
3074
|
if (options.approveMergeUpgradeOptions) {
|
|
2283
3075
|
addApproveMergeUpgradeWorkflow(this, options.approveMergeUpgradeOptions);
|
|
2284
3076
|
}
|
|
3077
|
+
if (options.projectMetadata !== false) {
|
|
3078
|
+
new ProjectMetadata(
|
|
3079
|
+
this,
|
|
3080
|
+
typeof options.projectMetadata === "object" ? options.projectMetadata : {}
|
|
3081
|
+
);
|
|
3082
|
+
}
|
|
3083
|
+
if (options.agentConfig) {
|
|
3084
|
+
new AgentConfig(this, options.agentConfigOptions);
|
|
3085
|
+
}
|
|
2285
3086
|
if (this.buildWorkflow) {
|
|
2286
3087
|
addBuildCompleteJob(this.buildWorkflow);
|
|
2287
3088
|
}
|
|
@@ -2340,9 +3141,9 @@ var MonorepoProject = class extends TypeScriptAppProject {
|
|
|
2340
3141
|
|
|
2341
3142
|
// src/typescript/typescript-config.ts
|
|
2342
3143
|
import { relative as relative3 } from "path";
|
|
2343
|
-
import { Component as
|
|
3144
|
+
import { Component as Component14 } from "projen";
|
|
2344
3145
|
import { ensureRelativePathStartsWithDot } from "projen/lib/util/path";
|
|
2345
|
-
var TypeScriptConfig = class extends
|
|
3146
|
+
var TypeScriptConfig = class extends Component14 {
|
|
2346
3147
|
constructor(project) {
|
|
2347
3148
|
super(project);
|
|
2348
3149
|
let tsPaths = {};
|
|
@@ -2369,13 +3170,13 @@ var TypeScriptConfig = class extends Component13 {
|
|
|
2369
3170
|
};
|
|
2370
3171
|
|
|
2371
3172
|
// src/workflows/aws-deploy-workflow.ts
|
|
2372
|
-
var
|
|
2373
|
-
import { Component as
|
|
3173
|
+
var import_utils10 = __toESM(require_lib());
|
|
3174
|
+
import { Component as Component15 } from "projen";
|
|
2374
3175
|
import { BuildWorkflow } from "projen/lib/build";
|
|
2375
3176
|
import { GitHub } from "projen/lib/github";
|
|
2376
3177
|
import { JobPermission as JobPermission4 } from "projen/lib/github/workflows-model";
|
|
2377
3178
|
var PROD_DEPLOY_NAME = "prod-deploy";
|
|
2378
|
-
var AwsDeployWorkflow = class _AwsDeployWorkflow extends
|
|
3179
|
+
var AwsDeployWorkflow = class _AwsDeployWorkflow extends Component15 {
|
|
2379
3180
|
constructor(project, options = {}) {
|
|
2380
3181
|
super(project);
|
|
2381
3182
|
this.project = project;
|
|
@@ -2386,7 +3187,7 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends Component14 {
|
|
|
2386
3187
|
* @deprecated Use deployment target role terminology elsewhere. This property is maintained for backward compatibility.
|
|
2387
3188
|
* @default 'primary' (this is the only type supported currently)
|
|
2388
3189
|
*/
|
|
2389
|
-
this.awsEnvironmentType =
|
|
3190
|
+
this.awsEnvironmentType = import_utils10.DEPLOYMENT_TARGET_ROLE.PRIMARY;
|
|
2390
3191
|
this.setupNode = () => {
|
|
2391
3192
|
return [
|
|
2392
3193
|
{
|
|
@@ -2496,7 +3297,7 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends Component14 {
|
|
|
2496
3297
|
}
|
|
2497
3298
|
const turbo = TurboRepo.of(this.rootProject);
|
|
2498
3299
|
const buildWorkflowOptions = turbo?.remoteCacheOptions ? TurboRepo.buildWorkflowOptions(turbo.remoteCacheOptions) : {};
|
|
2499
|
-
this.awsStageType = options.awsStageType ??
|
|
3300
|
+
this.awsStageType = options.awsStageType ?? import_utils10.AWS_STAGE_TYPE.DEV;
|
|
2500
3301
|
this.awsDeploymentTargets = options.awsDeploymentTargets ?? AwsDeploymentConfig.of(project)?.awsDeploymentTargets.filter(
|
|
2501
3302
|
(target) => target.awsStageType === this.awsStageType && target.ciDeployment
|
|
2502
3303
|
) ?? [];
|
|
@@ -2656,6 +3457,7 @@ export {
|
|
|
2656
3457
|
MonorepoProject,
|
|
2657
3458
|
PROD_DEPLOY_NAME,
|
|
2658
3459
|
PnpmWorkspace,
|
|
3460
|
+
ProjectMetadata,
|
|
2659
3461
|
ROOT_CI_TASK_NAME,
|
|
2660
3462
|
ROOT_TURBO_TASK_NAME,
|
|
2661
3463
|
ResetTask,
|
|
@@ -2671,6 +3473,15 @@ export {
|
|
|
2671
3473
|
Vitest,
|
|
2672
3474
|
addApproveMergeUpgradeWorkflow,
|
|
2673
3475
|
addBuildCompleteJob,
|
|
2674
|
-
|
|
3476
|
+
awsCdkBundle,
|
|
3477
|
+
baseBundle,
|
|
3478
|
+
getLatestEligibleVersion,
|
|
3479
|
+
jestBundle,
|
|
3480
|
+
pnpmBundle,
|
|
3481
|
+
projenBundle,
|
|
3482
|
+
resolveTemplateVariables,
|
|
3483
|
+
turborepoBundle,
|
|
3484
|
+
typescriptBundle,
|
|
3485
|
+
vitestBundle
|
|
2675
3486
|
};
|
|
2676
3487
|
//# sourceMappingURL=index.mjs.map
|